Android⾼级UI(⼀),UI绘制流程及原理
会讲到⾃定义View的时候为什么要重写onMeasure()⽅法。
⼀ ⽤户的R.layout.l加载到window的流程
⾸先系统会创建⼀个顶层容器DecorView,是继承framelayout的viewgroup。 DecorView是Phonewindow.java持有的⼀个实例。
在系统内部帮我们初始化好了DecorView对象, 然后根据activity主题的不同⽽加载不同的l, ⽐如NoActionBar, DarkActionBar等。
不管是哪个l, 都会有⼀个⼀样的Framelayout, id是 com.android.internal.t
在顶层布局中加载基础布局Framelayout,
开发者通过activity的setContentView(), 把activity_l添加到ContentView中。再将ContentView添加到基础布局中的Framelayout中。
在这个路径下⾯:制作android软件流程
C:\Users\xxx\AppData\Local\Android\sdk\platforms\android-28\data\res\layout\
有⼏个screen的xml⽂件,分别是:
screen_l
screen_l
l
l
screen_simple_overlay_l
screen_l
l
screen_l
l
最终加载哪⾥⼀个screen⽂件,是根据Activty的theme来的。
以screen_simple为例:
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/layout/l
This is an optimized layout for a screen, with the minimum set of features enabled.
-->
<LinearLayout xmlns:android="schemas.android/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
public static final int ID_ANDROID_CONTENT = com.android.internal.t protected ViewGroup generateLayout(DecorView decor) {
...
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); ...
}
我们的acitvity_l是加载到l的FrameLayout⾥⾯的。
@Override
public 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)) {
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = SceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
}
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. 在ActivityThread.handleResumeActivity()⽅法中调⽤,
ViewManager wm = a.getWindowManager();
wm.addView(decor, l);
5. 最终⼜调⽤到windowManagerGlobal.addView();
6. 在windowManagerGlobal⾥⾯⽣产ViewRootImpl. 添加顶层view, 也就是decor view。
7. 最后在ViewRootImpl⾥进⾏三⼤步骤。
1. onMeasure()
关于onMeasure(), 必须搞清楚MeasureSpec的含义。
View = 模式 + 尺⼨->MeasureSpec 32位int值
00000000000000000000000000000000
MODE_MASK : 11000000000000000000000000000000
~MODE_MASK: 00111111111111111111111111111111
SpecMode(前2位) + SpecSize(后30)
public static final int UNSPECIFIED = 0 << MODE_SHIFT; 00000000000000000000000000000000⽗容器不对View做任何限制,系统内部使⽤
public static final int EXACTLY = 1 << MODE_SHIFT; 01000000000000000000000000000000⽗容器检测出View的⼤⼩,Vew的⼤⼩就是SpecSize LayoutPamras match_parent 固定⼤⼩
public static final int AT_MOST = 2 << MODE_SHIFT; 10000000000000000000000000000000⽗容器指定⼀个可⽤⼤⼩,View的⼤⼩不能超过这个值,LayoutPamras wrap_content
mode + size --> MeasureSpec
MeasureSpec = mode + size
以FrameLayout的onMeasure为例。如果FrameLayout的layout_width和layout_height都是wrap_content.那么FrameLayout需要知道⼦控件的最⼤宽和最⼤⾼, 才能确定FrameLayout⾃⾝的宽⾼。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论