您的位置:首页 > 运维架构

PopupWindow的创建过程

2015-05-29 10:43 387 查看
各位大大我也是初学者,写这些主要是为了对其认识更加清晰,同时也为了以后忘记时可以快速的回忆起。这是我第一次看源码在结合其他大大的思想得到的总结,可能会有很多问题,如果你们发现怎么不对可以告诉我,我很希望能得到你们的评论

 

这次写这个PopupWindow的创建过程,其实很多地方我也不是很了解。不过我想还是写出来吧,有什么不对的或者哪里不完善的,等学了后面的内容再改吧,到时候新知识结合以前的理解可能会更好的去了解。下面就看看我是怎么理解PopupWindow的创建过程的。

1.通过构造函数创建PopupWindow对象。该对象只是个空壳子。

2.通过setContextView来给弹窗设置弹窗视图组件View

3.通过上面创建的对象中的方法showAsDropDown或showAtLocation来显示该子窗口。这两个方法唯一的区别就是显示的位置不一样,但是其内部的流程是一样的。下面就让我们一起看看showAtLocation这个方法内部实现过程。

public void showAtLocation(IBinder token, int gravity, int x, int y) {
if (isShowing() || mContentView == null) {
return;
}

//1.删除注册的滚动变化监听事件
unregisterForScrollChanged();

mIsShowing = true;
mIsDropdown = false;

//2.创建一个参数token为token的布局
WindowManager.LayoutParams p = createPopupLayout(token);
//3.获取窗口动画资源样式
 p.windowAnimations = computeAnimationResource();

//4.创建了一个窗口,并将视图内容加入到里面
preparePopup(p);
if (gravity == Gravity.NO_GRAVITY) {
gravity = Gravity.TOP | Gravity.START;
}
p.gravity = gravity;
p.x = x;
p.y = y;
if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
//5.将子窗口和父窗口关联,并创建一个RootView,将子窗口和RootView绑定
 invokePopup(p);
}      以上就是显示子窗口的过程,大致步骤大家可以看我的代码注释,当我写到这里的时候我突然感觉这个过程和Activity创建的过程是那么的相似。也是首先创建一个空壳对象(activity),然后在创建窗口视图,并将窗口视图和RootView。不同的是创建对象不同,后面都是一样的。但是这里我们发现了没有,PopupWindow是没有自己window对象,这导致PopupWindow是一个纯窗口。因为window有菜单概念,而且还有系统按键,比如“home”,"menu"等。而纯窗口是没有这些的,它所有的用户消息处理的工作都是ViewGroup/View来完成的。对了PopupWindow他是没有自己Context对象的,他的对象就是父视图Activity的Context(注意Dialog是有的)。现在我们在来看看的窗口视图创建的过程。
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;
}

//1.创建一个容器(窗口视图),这个容器是用来装载通过上面setContextView设置的视图。
//其实这个容器就是FrameLayout的子类,而FrameLayout又是ViewGroup的子类
 PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, height
);
popupViewContainer.setBackgroundDrawable(mBackground);
//2.将视图组件mContentView装到容器popupViewContainer中
 popupViewContainer.addView(mContentView, listParams);

mPopupView = popupViewContainer;
} else {
mPopupView = mContentView;
}
mPopupViewInitialLayoutDirectionInherited =
(mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
mPopupWidth = p.width;
mPopupHeight = p.height;
}
     
通过上面代码分析我们可以看出其实创建视图的过程是和Activity相似的,不同的是activity的容器是DectorView,  而PopupWindow是PopupViewContainer 。
      最后我们在看下为什么 invokePopup这个方法为什么能将子窗口和父窗口关联,并创建一个RootView,将子窗口和RootView绑定的呢?看下面代码:

private void invokePopup(WindowManager.LayoutParams p) {
if (mContext != null) {
p.packageName = mContext.getPackageName();
}
mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
setLayoutDirectionFromAnchor();
mWindowManager.addView(mPopupView, p);
}
      额,限制我明白了 原来他是用了和Activity同一的方法addView。搜嘎。

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息