zoukankan      html  css  js  c++  java
  • Android Popupwindow 拖动

    版本号: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定义好的。





  • 相关阅读:
    LOJ 3055 「HNOI2019」JOJO—— kmp自动机+主席树
    LOJ 2586 「APIO2018」选圆圈——KD树
    bzoj 3600 没有人的算术——二叉查找树动态标号
    bzoj 1257 余数之和 —— 数论分块
    bzoj 3998 弦论 —— 后缀自动机
    bzoj 2946 公共串 —— 后缀自动机
    bzoj 4032 [ HEOI 2015 ] 最短不公共子串 —— 后缀自动机+序列自动机
    bzoj 2555 SubString —— 后缀自动机+LCT
    洛谷 P3804 [模板] 后缀自动机
    洛谷 P4106 / bzoj 3614 [ HEOI 2014 ] 逻辑翻译 —— 思路+递归
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/3843033.html
Copyright © 2011-2022 走看看