Android高级UI(一),UI绘制流程及原理

Android高级UI(一),UI绘制流程及原理

2023年7月15日发(作者:)

Android⾼级UI(⼀),UI绘制流程及原理会讲到⾃定义View的时候为什么要重写onMeasure()⽅法。⼀ ⽤户的y_加载到window的流程⾸先系统会创建⼀个顶层容器DecorView,是继承framelayout的viewgroup。 DecorView是持有的⼀个实例。在系统内部帮我们初始化好了DecorView对象, 然后根据activity主题的不同⽽加载不同的screen_, ⽐如NoActionBar,DarkActionBar等。不管是哪个screen_, 都会有⼀个⼀样的Framelayout, id是 t在顶层布局中加载基础布局Framelayout,开发者通过activity的setContentView(), 把activity_xxx_添加到ContentView中。再将ContentView添加到基础布局中的Framelayout中。在这个路径下⾯:C:UsersxxxAppDataLocalAndroidsdkplatformsandroid-28datareslayout有⼏个screen的xml⽂件,分别是:een_action_een_custom_een_een_een_simple_overlay_action_een_swipe_een_een_title_een_最终加载哪⾥⼀个screen⽂件,是根据Activty的theme来的。以screen_simple为例: public static final int ID_ANDROID_CONTENT = tprotected ViewGroup generateLayout(DecorView decor) {...ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);...}我们的acitvity_xxx_是加载到的FrameLayout⾥⾯的。@Overridepublic void setContentView(int layoutResID) { // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { AllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = neForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { e(layoutResID, mContentParent); } tApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { entChanged(); } mContentParentExplicitlySet = true;}对window的颜⾊,背景等修改,其实际上就是对DecorView修改。⽽且是通过设置Window Style⽅法, 在 PhoneWindow会专门读取style的值,并且相应的设置。⼆, 绘制view的流程:1. WindowManagerGlobal的作⽤域是整个App。 它缓存了整个App的Activity的DecorView对象,以及ViewRootImpl对象。2. WindowManagerImpl是对WindowManagerGlobal操作的封装。它的addView RemoveView UpdateView 都是针对WindowManagerGlobal缓存的Activity DecorView对象3. 在主线程ActivityThread中, 接到resume acticty的hanlder message, 也就是 RESUME_ACTIVITY。4. 在ResumeActivity()⽅法中调⽤,

ViewManager wm = dowManager();w(decor, l);5. 最终⼜调⽤到w();6. 在windowManagerGlobal⾥⾯⽣产ViewRootImpl. 添加顶层view, 也就是decor view。7. 最后在ViewRootImpl⾥进⾏三⼤步骤。1. onMeasure()关于onMeasure(), 必须搞清楚MeasureSpec的含义。View = 模式 + 尺⼨->MeasureSpec 32位int值00000000MODE_MASK : 11000000~MODE_MASK: 111111111SpecMode(前2位) + SpecSize(后30) public static final int UNSPECIFIED = 0 << MODE_SHIFT; 00000000⽗容器不对View做任何限制,系统内部使⽤

public static final int EXACTLY = 1 << MODE_SHIFT; 00000000⽗容器检测出View的⼤⼩,Vew的⼤⼩就是SpecSize LayoutPamras match_parent 固定⼤⼩

public static final int AT_MOST = 2 << MODE_SHIFT; 10000000⽗容器指定⼀个可⽤⼤⼩,View的⼤⼩不能超过这个值,LayoutPamras wrap_contentmode + size --> MeasureSpecMeasureSpec = mode + size 以FrameLayout的onMeasure为例。如果FrameLayout的layout_width和layout_height都是wrap_content.那么FrameLayout需要知道⼦控件的最⼤宽和最⼤⾼, 才能确定FrameLayout⾃⾝的宽⾼。 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); final boolean measureMatchParentChildren = e(widthMeasureSpec) != Y || e(heightMeasureSpec) != Y; (); int maxHeight = 0; int maxWidth = 0;//确定⼦控件的最⼤宽和最⼤⾼ for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (mMeasureAllChildren || ibility() != GONE) { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); final LayoutParams lp = (LayoutParams) outParams(); maxWidth = (maxWidth, suredWidth() + rgin + argin); maxHeight = (maxHeight, suredHeight() + gin + Margin); childState = combineMeasuredStates(childState, suredState()); if (measureMatchParentChildren) { if ( == _PARENT || == _PARENT) { (child); } } } }

//还有⼀些padding的设置 // Account for padding too maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground(); maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();//以及最⼤最⼩宽⾼的设置

// Check against our minimum height and width maxHeight = (maxHeight, getSuggestedMinimumHeight()); maxWidth = (maxWidth, getSuggestedMinimumWidth()); // Check against our foreground's minimum height and width final Drawable drawable = getForeground(); if (drawable != null) { maxHeight = (maxHeight, imumHeight()); maxWidth = (maxWidth, imumWidth()); }//最后通过setMeasuredDimension确定⾃⼰的真实宽⾼ setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT));

}

很重要的⼀点:ViewGroup measure --> onMeasure(测量⼦控件的宽⾼)--> setMeasuredDimension -->setMeasuredDimensionRaw(保存⾃⼰的宽⾼)View measure --> onMeasure --> setMeasuredDimension -->setMeasuredDimensionRaw(保存⾃⼰的宽⾼)在View的默认OnMeasure()⽅法中,getDefaultSize()获取到的值就是⾃⾝的宽⾼,match_parent == wrap_content 的情况是⼀样的,所以⾃定义View时需要重写onMeasure()。以动态确定你想要的ted void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = e(measureSpec); int specSize = e(measureSpec); switch (specMode) { case IFIED: result = size; break; case _MOST://match_parent == wrap_content 的情况是⼀样的,所以⾃定义View时需要重写onMeasure()。 case Y: result = specSize; break; } return result;}

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689428666a246641.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信