版本号:1.0

日期:2014.4.29

版权:© 2014 kince 转载注明出处

关于View的拖动大家应该比較了解了,比方对一个控件IamgeView拖动,或者一个视图View拖动,实现方式也非常easy,继承OnTouchListener接口,然后重写onTouch方法,在触屏事件进行处理就可以。可是Popupwindow怎样实现拖动呢,我们都知道它和普通的View不一样,由于它不是继承于View类的,可是它的实现却是和View密切相关的,由于我们都知道Android视图的显示都是由View来处理的,所以一定离不开它。从Popupwindow的实现就能够看出来,

import com.android.internal.R;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.os.IBinder;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.WindowManager; import java.lang.ref.WeakReference;

上面是它的导包情况,基本上不是和View相关,就是和画图相关。因此关于Popupwindow的拖动这一块,也和View有联系。首先看一下它的API,看一看有没有和View移动、变化相关的方法,果然在最后有几个update()方法,例如以下:

update()方法用来更新Popupwindow的位置和大小的,那么问题就好攻克了。看代码:

package com.example.drag_and_drop_movablepopupwindow;

import android.support.v7.app.ActionBarActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.TextView; public class MainActivity extends ActionBarActivity { private Button btnOpenPopup; private int mCurrentX;
private int mCurrentY; private PopupWindow mPopup; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
btnOpenPopup = (Button) findViewById(R.id.openpopup);
btnOpenPopup.setOnClickListener(new Button.OnClickListener() { @Override
public void onClick(View arg0) {
creatPopubWindow_1();
}
});
} /**
* 1
*/
private void creatPopubWindow_1() {
LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
.getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(popupView,
200, 200); Button btnDismiss = (Button) popupView.findViewById(R.id.dismiss);
btnDismiss.setOnClickListener(new Button.OnClickListener() { @Override
public void onClick(View v) {
popupWindow.dismiss();
}
}); popupWindow.showAsDropDown(btnOpenPopup, 50, 50); popupView.setOnTouchListener(new OnTouchListener() {
int orgX, orgY;
int offsetX, offsetY; @Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
orgX = (int) event.getX();
orgY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
offsetX = (int) event.getRawX() - orgX;
offsetY = (int) event.getRawY() - orgY;
popupWindow.update(offsetX, offsetY, -1, -1, true);
break;
}
return true;
}
});
}
}

效果如图:

首先对Popupwindow设置触摸事件,然后在回调方法中进行计算,假设手指拖动了Popupwindow,那么就调用update()方法来更新它的位置。有些同学可能不太理解參数-1是什么意思,在上面的API中,写明的是宽和高,这里怎么变成-1了呢,看一下Popupwindow源码就明确了。

 /**
* <p>Updates the position and the dimension of the popup window. Width and
* height can be set to -1 to update location only. Calling this function
* also updates the window with the current popup state as
* described for {@link #update()}.</p>
*
* @param x the new x location
* @param y the new y location
* @param width the new width, can be -1 to ignore
* @param height the new height, can be -1 to ignore
* @param force reposition the window even if the specified position
* already seems to correspond to the LayoutParams
*/
public void update(int x, int y, int width, int height, boolean force) {
if (width != -1) {
mLastWidth = width;
setWidth(width);
} if (height != -1) {
mLastHeight = height;
setHeight(height);
} if (!isShowing() || mContentView == null) {
return;
} WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams(); boolean update = force; final int finalWidth = mWidthMode < 0 ? mWidthMode : mLastWidth;
if (width != -1 && p.width != finalWidth) {
p.width = mLastWidth = finalWidth;
update = true;
} final int finalHeight = mHeightMode < 0 ? mHeightMode : mLastHeight;
if (height != -1 && p.height != finalHeight) {
p.height = mLastHeight = finalHeight;
update = true;
} if (p.x != x) {
p.x = x;
update = true;
} if (p.y != y) {
p.y = y;
update = true;
} final int newAnim = computeAnimationResource();
if (newAnim != p.windowAnimations) {
p.windowAnimations = newAnim;
update = true;
} final int newFlags = computeFlags(p.flags);
if (newFlags != p.flags) {
p.flags = newFlags;
update = true;
} if (update) {
setLayoutDirectionFromAnchor();
mWindowManager.updateViewLayout(mPopupView, p);
}
}

前两个if推断已经说得非常清楚了,假设參数是-1的话,就不改变Popupwindow的大小了,由于我们仅仅是移动位置,所以才这样写。那关于Popupwindow的移动最后是怎么实现的呢,能够看出就是调用WindowManager的updateViewLayout()方法,这种方法在WindowManager中并没有实现,它是ViewManager接口里面的方法,WindowManager继承了ViewManager。说到ViewManager,它里面定义的方法都非经常常使用,看代码:

/** Interface to let you add and remove child views to an Activity. To get an instance
* of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
*/
public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a second view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* secondary {@link Display} and the specified display can't be found
* (see {@link android.app.Presentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}

这下大家应该明了,我们经经常使用的addView、removeView方法就是在这里面定义的,那么谁去实现呢?就是Layout控件,比方LinearLayout、RelativeLayout等,所以我们刚才用的updateViewLayout()方法也是在xml布局文件里的layout定义好的。

Android Popupwindow 拖动的更多相关文章

  1. Android PopupWindow Dialog 关于 is your activity running 崩溃详解

    Android PopupWindow Dialog 关于 is your activity running 崩溃详解 [TOC] 起因 对于 PopupWindow Dialog 需要 Activi ...

  2. Android PopupWindow的使用和分析

    Android PopupWindow的使用和分析 PopupWindow使用 PopupWindow这个类用来实现一个弹出框,可以使用任意布局的View作为其内容,这个弹出框是悬浮在当前activi ...

  3. Android PopupWindow的使用技巧(转)

    Android PopupWindow的使用技巧 PopupWindow是Android上自定义弹出窗口,使用起来很方便. PopupWindow的构造函数为 public PopupWindow(V ...

  4. [Android实例] 拖动滑块进行图片拼合验证方式的实现

    该篇文章从eoeAndroid搬迁过来的,原文地址:[Android实例] 拖动滑块进行图片拼合验证方式的实现 现在网站上有各种各样的验证码验证方式,比如计算大小,输入图片内容等,今天在一家网站上看到 ...

  5. android 可拖动控件 ontouchevent

    首先附上文章的转载内容的链接: 学习android 可拖动事件首先需要对android的屏幕和touchevent参数建立一个详细的知识结构. 1.android坐标系统 一.首先明确一下 andro ...

  6. Android popupwindow使用心得(一)

    最近项目中好多地方用到popupwindow,感觉这个控件还是非常重要的.所以把使用心得总结下,废话不多说,直接上代码. public class MainActivity extends Activ ...

  7. 不得不吐槽的Android PopupWindow的几个痛点(实现带箭头的上下文菜单遇到的坑)

    说到PopupWindow,我个人感觉是又爱又恨,没有深入使用之前总觉得这个东西应该很简单,很好用,但是真正使用PopupWindow实现一些效果的时候总会遇到一些问题,但是即便是人家的api有问题, ...

  8. Android -- PopupWindow(其中嵌套ListView 可以被点击)

    1. 效果图

  9. android PopupWindow使用实例

    注:点空白或菜单外隐藏popupwindow菜单: 但是,若点击有点击事件的组件则要再写代码手动隐藏: @Override public boolean onTouchEvent(MotionEven ...

随机推荐

  1. Codeforces 306B

    #include <cstdio> #include <algorithm> #include <cstring> #include <cstdlib> ...

  2. [amazonaccess 1]logistic.py 特征提取

    ---恢复内容开始--- 本文件对应logistic.py amazonaccess介绍: 根据入职员工的定位(员工角色代码.角色所属家族代码等特征)判断员工是否有访问某资源的权限 logistic. ...

  3. HTTP的头部

    if($this->GetHead("http-edition")=="HTTP/1.1") $httpv = "HTTP/1.1"; ...

  4. update慢怎样处理?

    update慢: 1.表的pctfree參数设置? 2.运行计划用索引还是全表扫? 3.SQL语句写法问题? 4.update慢还是commit慢? 5.更新多少条数据? 6.表是否频繁update造 ...

  5. 使用c#获取access中所有表的表名与内容

    以前在网上查过,似乎也可以通过读取access系统表的方法来获得,但是实在想不想来是什么,今天又在网上找了找,终于发现更加方便的方法,更重要的是,这种方法也可以通用所有OLEDB数据源. 这里用到了O ...

  6. KeystoneJS+mongo搭建简易博客

    KeystoneJS 是一款基于 Express 和 MongoDB 的开源免费 Node.js CMS 网站开发框架. 一. 安装node.js,mongodb 二. 命令行安装KeystoneJS ...

  7. JAVA 年轻代收集器 第九节

    JAVA 年轻代收集器  第九节 继续上一章所讲的,STW即GC时候的停顿时间,他会暂停我们程序中的所有线程.如果STW所用的时间长而且次数多的话,那么我们整个系统稳定性以及可用性将大大降低. 因此我 ...

  8. JVM学习之GC常用算法

    出处:博客园左潇龙的技术博客--http://www.cnblogs.com/zuoxiaolong,多谢分享 GC策略解决了哪些问题? 既然是要进行自动GC,那必然会有相应的策略,而这些策略解决了哪 ...

  9. OC语法9——Category类别

    Category(分类): 当我们在开发过程中要给类添加新的方法时,一般不要去动原类. 再不改动原类的限制下,怎么拓展类的方法?以往我们的做法是新建子类使其继承该类,然后通过子类拓展类的行为. OC提 ...

  10. this的用法this.name=name 这个什么意思

    public Employee(string name, string alias){ // Use this to qualify the fields, name and alias: this. ...