Popupwindow

Popupwindow 拖动

关于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定义好的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寂-静

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值