Android高级UI学习记录(UI的绘制流程)

上篇文章是App的启动的流程这篇学习Activity中的布局文件是如何绘制的。先从onCreate的setContentView开始。先看下Activity的绘制过程

##Activity

public void setContentView(@LayoutRes int layoutResID) {

getWindow().setContentView(layoutResID);//getWindow拿到的是PhoneWindow

initWindowDecorActionBar();

}

##PhoneWindow

public void setContentView(int layoutResID) {

...

if (mContentParent == null) {

installDecor();//初始化DecorView

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

mContentParent.removeAllViews();

}

...

}

private void installDecor() {//导航栏什么的在这个方法中设置

...

mContentParent = generateDecor(-1);//创建DecorView

...

mContentParent = generateLayout(mDecor);//设置DecorView布局

...

}

protected DecorView generateDecor(int featureId) {

...

return new DecorView(context, featureId, this, getAttributes());

}

protected ViewGroup generateLayout(DecorView decor) {

// 获取AndroidManifest.xml中指定的themes主题

TypedArray a = getWindowStyle();

...

if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {

requestFeature(FEATURE_NO_TITLE);

} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) { // Don't allow an action bar if there is no title. requestFeature(FEATURE_ACTION_BAR);

} if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {

requestFeature(FEATURE_ACTION_BAR_OVERLAY);

} if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {

requestFeature(FEATURE_ACTION_MODE_OVERLAY);

} if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {

requestFeature(FEATURE_SWIPE_TO_DISMISS);

} if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {

setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));

} if (a.getBoolean(R.styleable.Window_windowTranslucentStatus, false)) {

setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS & (~getForcedWindowFlags()));

} if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation, false)) {

setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION & (~getForcedWindowFlags()));

} if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {

setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));

} if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {

setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));

} if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch, getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)) {

setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));

}

a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);

a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);

if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString() + ", major: " + mMinWidthMajor.coerceToString());

if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {

if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedWidthMajor, mFixedWidthMajor);

} if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {

if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedWidthMinor, mFixedWidthMinor);

} if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {

if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedHeightMajor, mFixedHeightMajor);

} if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {

if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedHeightMinor, mFixedHeightMinor);

} if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {

requestFeature(FEATURE_CONTENT_TRANSITIONS);

} if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {

requestFeature(FEATURE_ACTIVITY_TRANSITIONS);

} mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);

...

if (!mForcedStatusBarColor) {

mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);

} if (!mForcedNavigationBarColor) {

mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000); mNavigationBarDividerColor = a.getColor(R.styleable.Window_navigationBarDividerColor, 0x00000000);

}

...

int layoutResource; //DecorView 的布局文件

int features = getLocalFeatures();

// System.out.println("Features: 0x" + Integer.toHexString(features));

if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {

layoutResource = R.layout.screen_swipe_dismiss; setCloseOnSwipeEnabled(true);

} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {

if (mIsFloating) {

TypedValue res = new TypedValue(); getContext().getTheme().resolveAttribute( R.attr.dialogTitleIconsDecorLayout, res, true); layoutResource = res.resourceId;

} else {

layoutResource = R.layout.screen_title_icons;

}

// XXX Remove this once action bar supports these features. removeFeature(FEATURE_ACTION_BAR);

// System.out.println("Title Icons!");

} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {

// Special case for a window with only a progress bar (and title).

// XXX Need to have a no-title version of embedded windows. layoutResource = R.layout.screen_progress;

// System.out.println("Progress!");

} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {

// Special case for a window with a custom title.

// If the window is floating, we need a dialog layout

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute( R.attr.dialogCustomTitleDecorLayout, res, true);

layoutResource = res.resourceId;

} else {

layoutResource = R.layout.screen_custom_title;

}

// XXX Remove this once action bar supports these

features. removeFeature(FEATURE_ACTION_BAR);

} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {

// If no other features and not embedded, only need a title.

// If the window is floating, we need a dialog layout

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute( R.attr.dialogTitleDecorLayout, res, true);

layoutResource = res.resourceId;

} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {

layoutResource = a.getResourceId( R.styleable.Window_windowActionBarFullscreenDecorLayout, R.layout.screen_action_bar);

} else {

layoutResource = R.layout.screen_title;

}

// System.out.println("Title!");

} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {

layoutResource = R.layout.screen_simple_overlay_action_mode;//DecorView 的布局文件配置

} else {

// Embedded, so no decoration is needed.

layoutResource = R.layout.screen_simple;//DecorView 的布局文件配置

// System.out.println("Simple!");

}

mDecor.startChanging();

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);//将自己写的布局文件解析

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

if (contentParent == null) {

throw new RuntimeException("Window couldn't find content container view");

} if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {

ProgressBar progress = getCircularProgressBar(false);

if (progress != null) { progress.setIndeterminate(true);

}

} if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {

registerSwipeCallbacks(contentParent);

}

...

return contentParent;

}

##R.layout.screen_simple_overlay_action_mode.xml 

 android:layout_width="match_parent" 

 android:layout_height="match_parent" 

 android:fitsSystemWindows="true">

 

 android:layout_width="match_parent"

 android:layout_height="match_parent"

 android:foregroundInsidePadding="false" 

 android:foregroundGravity="fill_horizontal|top"

 android:foreground="?android:attr/windowContentOverlay" /> 

 

 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" /> 

 

##R.layout.screen_simple.xml

 

 android:layout_width="match_parent"

 android:layout_height="match_parent" 

 android:fitsSystemWindows="true" 

 android:orientation="vertical"> 

 

 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" /> 

 

 android:layout_width="match_parent" 

 android:layout_height="match_parent"

 android:foregroundInsidePadding="false" 

 android:foregroundGravity="fill_horizontal|top" 

 android:foreground="?android:attr/windowContentOverlay" /> 

DecorView的布局文件可以看出其实我们写的布局文件其实是通过id为content的布局进行添加的

那接下来看看是如何解析我们写的布局的

##DecorView

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {//将View树

...

mDecorCaptionView = createDecorCaptionView(inflater);

final View root = inflater.inflate(layoutResource, null);

if (mDecorCaptionView != null) {

    if (mDecorCaptionView.getParent() == null) {

    addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

    }

    mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));

} else {

// Put it below the color views.

addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

}

mContentRoot = (ViewGroup) root;

initializeElevation();

}

private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {//DecorCaptionView 布局文件在这个方法中添加

DecorCaptionView decorCaptionView = null;

for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {

...

decorCaptionView = inflateDecorCaptionView(inflater);

...

return decorCaptionView;

}

private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {

final Context context = getContext();

// We make a copy of the inflater, so it has the right context associated with it.

inflater = inflater.from(context);

final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption, null);

setDecorCaptionShade(context, view); return view;

}

##R.layout.decor_caption.xml

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:descendantFocusability="beforeDescendants" >

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="end"

android:background="@drawable/decor_caption_title"

android:focusable="false"

android:descendantFocusability="blocksDescendants" >

你可能感兴趣的:(Android高级UI学习记录(UI的绘制流程))