`

PopupWindow

阅读更多
PopupWindow,实质是使用WindowManager添加的一个顶层View。

PopupWindow::preparePopup会判断是否有背景,有则创建自己的容器,没有则直接用传入的view。

private void preparePopup(WindowManager.LayoutParams p) {
        if (mContentView == null || mContext == null || mWindowManager == null) {
            throw new IllegalStateException("You must specify a valid content view by "
                    + "calling setContentView() before attempting to show the popup.");
        }

        if (mBackground != null) {
            final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
            int height = ViewGroup.LayoutParams.MATCH_PARENT;
            if (layoutParams != null &&
                    layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                height = ViewGroup.LayoutParams.WRAP_CONTENT;
            }

            // when a background is available, we embed the content view
            // within another view that owns the background drawable
            PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
            PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, height
            );
            popupViewContainer.setBackgroundDrawable(mBackground);
            popupViewContainer.addView(mContentView, listParams);

            mPopupView = popupViewContainer;
        } else {
            mPopupView = mContentView;
        }
        mPopupWidth = p.width;
        mPopupHeight = p.height;
    }


PopupViewContainer 是PopupWindow的内部类,里面有触摸事件的判断:
@Override
        public boolean onTouchEvent(MotionEvent event) {
            final int x = (int) event.getX();
            final int y = (int) event.getY();
            
            if ((event.getAction() == MotionEvent.ACTION_DOWN)
                    && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
                dismiss();
                return true;
            } else if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                dismiss();
                return true;
            } else {
                return super.onTouchEvent(event);
            }
        }


这就是为什么PopupWindow设置了背景setBackgroundDrawable后点击popupwindow外能隐去popupwindow。

触摸事件可以进行拦截,使用PopupWindow::setTouchInterceptor方法,这个对应于内部类PopupViewContainer 中的:

public boolean dispatchTouchEvent(MotionEvent ev) {
            if (mTouchInterceptor != null && mTouchInterceptor.onTouch(this, ev)) {
                return true;
            }
            return super.dispatchTouchEvent(ev);
        }

出入的拦截接听的返回结果很重要,true是直接消耗掉触摸事件,false则继续调用后面的触摸事件。

PopupWindow在退出activity前,如果没有dismiss方法,会报错。

例子(功能:PopWindow显示时,点击屏幕外,点击菜单键,返回键隐去):
package com.example.popwindow;

import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;

public class PopupWindowActivity extends Activity implements OnClickListener {
	PopupWindow pop;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_popup_window);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(this);
    }

	public void onClick(View v) {
		switch(v.getId()){
		case R.id.btn:
			popMenu();
			break;
		}
	}

	private void popMenu() {
		if(pop == null){
			View view = getLayoutInflater().inflate(R.layout.pop, null);
			//下面两句是必须添加滴,只有添加了这两个,才能设置key事件响应
			view.setFocusable(true);
			view.setFocusableInTouchMode(true);
			
			view.setOnKeyListener(new OnKeyListener() {
				public boolean onKey(View v, int keyCode, KeyEvent event) {
					int action = event.getAction();
					if(action == KeyEvent.ACTION_UP){
						if(keyCode == KeyEvent.KEYCODE_MENU){
							pop.dismiss();
							System.out.println("弹出层的view响应菜单键,隐藏pop层!");
							return true;
						}
					}
					return false;
				}
			});
			
			pop = new PopupWindow(view, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, true);
			//一定要有背景,PopWindow源码设计就是这样,有背景则响应弹出层外的点击,没有则不响应
			pop.setBackgroundDrawable(new BitmapDrawable());
		}
		pop.showAtLocation(getWindow().getDecorView(), Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM, 0, 0);
	}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics