public PopupWindow (Context context) public PopupWindow(View contentView) public PopupWindow(int width, int height) public PopupWindow(View contentView, int width, int height) public PopupWindow(View contentView, int width, int height, boolean focusable)
showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移 showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移 showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
具体如下所示
//创建对象 PopupWindow popupWindow = new PopupWindow(this); View inflate = LayoutInflater.from(this).inflate(R.layout.view_pop_custom, null); //设置view布局 popupWindow.setContentView(inflate); popupWindow.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT); popupWindow.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); //设置动画的方法 popupWindow.setAnimationStyle(R.style.BottomDialog); //设置PopUpWindow的焦点,设置为true之后,PopupWindow内容区域,才可以响应点击事件 popupWindow.setTouchable(true); //设置背景透明 popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); //点击空白处的时候让PopupWindow消失 popupWindow.setOutsideTouchable(true); // true时,点击返回键先消失 PopupWindow // 但是设置为true时setOutsideTouchable,setTouchable方法就失效了(点击外部不消失,内容区域也不响应事件) // false时PopupWindow不处理返回键,默认是false popupWindow.setFocusable(false); //设置dismiss事件 popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { } }); boolean showing = popupWindow.isShowing(); if (!showing){ //show,并且可以设置位置 popupWindow.showAsDropDown(mTv1); }
先看问题代码,下面这个不会出现弹窗,思考:为什么?
PopupWindow popupWindow = new PopupWindow(this); View inflate = LayoutInflater.from(this).inflate(R.layout.view_pop_custom, null); popupWindow.setContentView(inflate); popupWindow.setAnimationStyle(R.style.BottomDialog); popupWindow.showAsDropDown(mTv1);
首先先来看看源码
可以看出,先判断是否show,如果没有showing的话,则进行contentView赋值,如果mWindowManager为null,则取获取mWindowManager,这个很重要。最后便是根据SDK版本而不是在构造函数中设置附加InDecor的默认设置,因为构造函数中可能没有上下文对象。我们只想在这里设置默认,如果应用程序尚未设置附加InDecor。
public void setContentView(View contentView) { //判断是否show,如果已经show,则返回 if (isShowing()) { return; } //赋值 mContentView = contentView; if (mContext == null && mContentView != null) { mContext = mContentView.getContext(); } if (mWindowManager == null && mContentView != null) { mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); } //在这里根据SDK版本而不是在构造函数中设置附加InDecor的默认设置,因为构造函数中可能没有上下文对象。我们只想在这里设置默认,如果应用程序尚未设置附加InDecor。 if (mContext != null && !mAttachedInDecorSet) { setAttachedInDecor(mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP_MR1); }
}
public void setAttachedInDecor(boolean enabled) { mAttachedInDecor = enabled; mAttachedInDecorSet = true; }
先来看一下showAsDropDown(View anchor)部分代码
public void showAsDropDown(View anchor) { showAsDropDown(anchor, 0, 0); }
//主要看这个方法
//注意啦:关于更多内容,可以参考我的博客大汇总:https://github.com/yangchong211/YCBlogs
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (isShowing() || mContentView == null) {
return;
}
TransitionManager.endTransitions(mDecorView); //下面单独讲 //https://github.com/yangchong211/YCBlogs attachToAnchor(anchor, xoff, yoff, gravity); mIsShowing = true; mIsDropdown = true; //通过createPopupLayoutParams方法创建和初始化LayoutParams final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken()); preparePopup(p); final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, p.width, p.height, gravity); updateAboveAnchor(aboveAnchor); p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1; invokePopup(p);
}
接着来看看attachToAnchor(anchor, xoff, yoff, gravity)源码
关于四种引用的深入介绍可以参考我的这边文章:01.四种引用比较与源码分析
private void attachToAnchor(View anchor, int xoff, int yoff, int gravity) { detachFromAnchor(); final ViewTreeObserver vto = anchor.getViewTreeObserver(); if (vto != null) { vto.addOnScrollChangedListener(mOnScrollChangedListener); } final View anchorRoot = anchor.getRootView(); anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener); mAnchor = new WeakReference<>(anchor); mAnchorRoot = new WeakReference<>(anchorRoot); mIsAnchorRootAttached = anchorRoot.isAttachedToWindow(); mAnchorXoff = xoff; mAnchorYoff = yoff; mAnchoredGravity = gravity; }
接着看看dismissImmediate(View decorView, ViewGroup contentHolder, View contentView)源码
第三步,讲mDecorView,mBackgroundView置为null
private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) { // If this method gets called and the decor view doesn't have a parent, // then it was either never added or was already removed. That should // never happen, but it's worth checking to avoid potential crashes. if (decorView.getParent() != null) { mWindowManager.removeViewImmediate(decorView); } if (contentHolder != null) { contentHolder.removeView(contentView); } // This needs to stay until after all transitions have ended since we // need the reference to cancel transitions in preparePopup(). mDecorView = null; mBackgroundView = null; mIsTransitioningToDismiss = false; }
通过createDecorView(View contentView)方法可以知道,是PopupDecorView直接new出来的布局对象decorView,外面包裹了一层PopupDecorView,这里的PopupDecorView也是我们自定义的FrameLayout的子类,然后看一下里面的代码:
private class PopupDecorView extends FrameLayout { private TransitionListenerAdapter mPendingExitListener; public PopupDecorView(Context context) { super(context); } @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); } } }
new CustomPopupWindow.PopupWindowBuilder(this) //.setView(R.layout.pop_layout) .setView(contentView) .setFocusable(true) //弹出popWindow时,背景是否变暗 .enableBackgroundDark(true) //控制亮度 .setBgDarkAlpha(0.7f) .setOutsideTouchable(true) .setAnimationStyle(R.style.popWindowStyle) .setOnDissmissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { //对话框销毁时 } }) .create() .showAsDropDown(tv6,0,10);
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。