设为首页 - 加入收藏 焦点技术网
热搜:java
当前位置:首页 >

Android Popupwindow 拖动

2014-04-29 10:26:00.0 Android  
导读:版本:1.0日期:2014.4.29版权:© 2014 kince 转载注明出处  关于View的拖动大家应该比较了解了,比如对一个控件IamgeView拖动,或者一个视图View拖动,实现方式也很容易,继承OnTouchListener接口,然后重写onTouch方法,在触屏事件进行处理即可。但是Popupwindow如何实现拖动呢,我们都知道它和普通的View不一样,因为它不是继承于View类...。。。

版本:1.0

日期:2014.4.29

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


  关于View的拖动大家应该比较了解了,比如对一个控件IamgeView拖动,或者一个视图View拖动,实现方式也很容易,继承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源代码就明白了。

 /**     * 

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()}.

* * @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.     * 

Throws {@link android.view.WindowManager.BadTokenException} for certain programming * errors, such as adding a second view to a window without removing the first view. *

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定义好的。





(编辑: wangjinyu501)

网友评论