Android中View的相关知识(5)
来源:互联网 发布:xy苹果助手mac版 编辑:程序博客网 时间:2024/04/30 01:56
Android中View的相关知识(5)
@(Android)
在上一篇的文章Android中View的相关知识(4)中,我们讲解了setContentView方法中getWindow().setContentView();方法,即创建content视图的过程,在本章节,我们继续往下走,探索initWindowDecorActionBar();看看ActionBar是如何创建的~:
接着分析initWindowDecorActionBar();这一路~~
老规矩,从Activity开始,Activity的源码中提供了3个重载的setContentView的方法:
public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); } public void setContentView(View view) { getWindow().setContentView(view); initWindowDecorActionBar(); } public void setContentView(View view, ViewGroup.LayoutParams params) { getWindow().setContentView(view, params); initWindowDecorActionBar(); }
从这些
setContentView();
方法中,每个方法都有initWindowDecorActionBar();
但是当当前的Activity是另一个Activity的子Activity时,或者该Activity不含属性值Window.FEATURE_ACTION_BAR
,或者当前Activity已经有一个ActionBar时,initWindowDecorActionBar();
方法不进行任何操作,否则初始化ActionBar,并对其设置相应的属性。我们回到Activity类的
setContentView();
方法中,既然上面跟content有关,那么这个initWindowDecorActionBar();
方法肯定就是和Title有关的了。附上手机屏幕层次图
我们进入此方法中:
//Creates a new ActionBar, locates the inflated ActionBarView, initializes the ActionBar with the view, and sets mActionBarprivate void initWindowDecorActionBar() { Window window = getWindow(); // Initializing the window decor can change window feature flags. // Make sure that we have the correct set before performing the test below. window.getDecorView(); if (isChild() || !window.hasFeature(Window.FEATURE_ACTION_BAR) || mActionBar != null) { return; } mActionBar = new WindowDecorActionBar(this); mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp); mWindow.setDefaultIcon(mActivityInfo.getIconResource()); mWindow.setDefaultLogo(mActivityInfo.getLogoResource());
我们把源码中的注释加上,可以看到,此方法的作用就是创建一个ActionBar。
首先通过getWindow();
方法获得一个Window
对象,通过widnow.getDecorView();
方法获得mDecor
对象,(当然具体实现肯定是PhoneWindow
类)这个过程很熟悉,就是我们上面分析的installDecor()
的过程,这里不再讲解,然后进行判断(1.当前的Activity
是否嵌套在另一个Activity
中;2.当前Window
是否设置为有ActionBar
;3.ActionBar
是否为空)在这3个判断只要其中一个为真就直接返回,不创建ActionBar
了;如果上述条件不成立,再往下走,就是创建ActionBar
的过程以及它的各种属性的设置了。
首先new一个WindowDecorActionBar();
将其赋值给mActionBar
; 这个WindowDercorActionBar
就是ActionBar
的子类。可见具体的实现就是由这个WindowDecorActionBar
来操作了。
public class WindowDecorActionBar extends ActionBar implements ActionBarOverlayLayout.ActionBarVisibilityCallback { ... //省略了代码。 ... public WindowDecorActionBar(Activity activity) { mActivity = activity; Window window = activity.getWindow(); View decor = window.getDecorView(); boolean overlayMode = mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY); init(decor); if (!overlayMode) { mContentView = decor.findViewById(android.R.id.content); } } ...}
从上面的代码我们一步步分析,首先,传入
Activity
的参数,调用activity.getWindow();
方法获取到窗口对象Window
,然后调用widnow.getDecorView();
方法获取到decor对象,接着就是进行init();
这里有个boolean
判断,这是设置activity
的窗口属性的。FEATURE_ACTION_BAR_OVERLAY
是指覆盖在内容之上的ActionBar
。我们继续深入进入init();
方法
private void init(View decor) { mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById( com.android.internal.R.id.decor_content_parent); if (mOverlayLayout != null) { mOverlayLayout.setActionBarVisibilityCallback(this); } mDecorToolbar = getDecorToolbar(decor.findViewById(com.android.internal.R.id.action_bar)); mContextView = (ActionBarContextView) decor.findViewById( com.android.internal.R.id.action_context_bar); mContainerView = (ActionBarContainer) decor.findViewById( com.android.internal.R.id.action_bar_container); mSplitView = (ActionBarContainer) decor.findViewById( com.android.internal.R.id.split_action_bar); if (mDecorToolbar == null || mContextView == null || mContainerView == null) { throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + "with a compatible window decor layout"); } mContext = mDecorToolbar.getContext(); mContextDisplayMode = mDecorToolbar.isSplit() ? CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; // This was initially read from the action bar style final int current = mDecorToolbar.getDisplayOptions(); final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0; if (homeAsUp) { mDisplayHomeAsUpSet = true; } ActionBarPolicy abp = ActionBarPolicy.get(mContext); setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp); setHasEmbeddedTabs(abp.hasEmbeddedTabs()); final TypedArray a = mContext.obtainStyledAttributes(null, com.android.internal.R.styleable.ActionBar, com.android.internal.R.attr.actionBarStyle, 0); if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) { setHideOnContentScrollEnabled(true); } final int elevation = a.getDimensionPixelSize(R.styleable.ActionBar_elevation, 0); if (elevation != 0) { setElevation(elevation); } a.recycle(); }
首先通过
findViewById
的方式,获取到decor
的布局,并且赋值给ActionBarOverlayLayout
(其实,在实例化DecorView
的方法generateDecor();
中,就能看出,window
根据不同的features
加载不同的布局文件,)我们来画个图看下DecorView的结构~
从这个结构图和上面的代码可以看出
ActionBar
和SplitActionBar
本质上为ActionBarContainer
,里面放置的就是ActionBarView
或者ActionBarContextView
;
先来看这个容器:ActionBarContainer
:
/* *This class acts as a container for the action bar view and action mode context views. It applies special styles as needed to help handle animated transitions between them. */public class ActionBarContainer extends FrameLayout { ... //省略了其中的代码 ...}
可以看出
ActionBarContainer
本质上是个FrameLayout
,(这一点跟DecorView
有点类似),对这个类的注释很清楚,我把这个注释也粘了过来,注释说的是这个ActionBarContainer
充当的是ActionBarView
和ActionBarContextView
的容器,而且这个容器在处理特别的ActionBar
风格的时候,也要实现动画切换。好了,这个容器不用多讲,我们继续往下走,看看ActionBarView
和ActionBarContextView
:
public class ActionBarView extends AbsActionBarView implements DecorToolbar { ... public void initProgress() { ... } } public void initIndeterminateProgress() { ... } ... public void setSplitToolbar(boolean splitActionBar) { ... } ... public void setEmbeddedTabView(ScrollingTabContainerView tabs) { ... } public void setMenu(Menu menu, MenuPresenter.Callback cb) { ... } ... public void setCustomView(View view) { ... } ... public void setDisplayOptions(int options) { ... } ... public void setNavigationMode(int mode) { ... } ... protected void onFinishInflate() { ... } ... private void initTitle() { ... } ... public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { ... } ...}
从代码中可以看出,
ActionBarView
的布局都是通过addView()
的方式进行创建的,我们就看看ActionBarView
类中到底哪些方法调用了addVIew();
我把使用过addView();
的方法全都列了出来。咱们进行分析:
inProgress();
和initIndeterminateProgress();
这两个方法都是初始化进度条的方法。前一个是水平进度条,后一个是圆形进度条。两个方法相差不大,首先,new 一个ProgressBar
赋值给相应的申明的ProgressView
;其次设置ProgressView
的各种属性,最后addView
将此ProgressView
加入到ActionBar
.
setSplitToolbar();
判断此ActionBar
是否需要split
,里面是初始化SpliteActionBar
的方法;里面也有各种的判断,需要就addView
将其加入;
setEmbeddedTabView();
它负责的把Tab
容器添加到ActionBarView
中,当NavigationMode=NAVIGATION_MODE_TABS
(页签)时,这个方法才有效;传入的参数tabs
是一个ScrollingTabContainerView
类型的对象,ScrollingTabContainerView
继承于HorizontalScrollView
,可以看出它是一个具备水平滚动条的tab容器;当ActionBarPolicy
的方法hasEmbeddedTabs
返回true
时,tab
就会embed
到ActionBarView
上,否则就会放到ActionBarContainer
上,借用网上的一张图表示下这个方法的调用过程:
setMenu();
这个是设置ActionBar上菜单的方法,在这个方法中,系统会把menuView
放到ActionBar
中;
setCustomView();
这个方法是把自定义View
放置到ActionBarView
上;调用的过程借用网上的一张图来展示:
setDisplayOptions();
这个是设置ActionBar
显示选项的方法。根据不同的options
;设置不同的ActionBar
显示;setNavigationMode();
这是设置ActionBar导航模式的方法,对于mode的值,有三个值可选:NAVIGATION_MODE_STANDARD
(标准)、NAVIGATION_MODE_LIST
(列表)、NAVIGATION_MODE_TABS
(页签),当mode=NAVIGATION_MODE_LIST
时,就会把spinner
控件放置到ActionBarView
上;当mode=NAVIGATION_MODE_TABS
时,就会把TabScrollView
控件放置到ActionBarView
上;onFinishInflate();
这是对布局进行inflate
后回调的方法,在这个方法中,会把mHomeLayout
先添加到mUpGoerFive
,然后再把mUpGoerFive
放置到ActionBarView
中,这个mUpGoerFive
是一个ViewGroup
,它里面包含两个视图:mHomeLayout
和mTitleLayout
,其中mHomeLayout
包含两个ImageView:mUpView
(即返回的指示图标)和mIconView
(默认情况下是应用程序图标),这两个View
分别可以通过getActionBar().setDisplayHomeAsUpEnabled()
和getActionBar().setDisplayShowHomeEnabled()
来设置是否显示;而mTitleLayout
是一个LinearLayout
;initTitle();
这个是初始化ActionBar
的Title
的方法。expandItemActionView();
这个是判断是否有扩展的菜单项的方法;
好了,ActonBarView
的这些主要的添加View
的方法已经看完了。我们接着往下走,看看ActionBarContextView
,其实光看名字,就知道它跟ActionBarView
差不多;
public class ActionBarContextView extends AbsActionBarView implements AnimatorListener { ... public void setSplitToolbar(boolean split) { ... } ... public void setCustomView(View view) { ... } ... private void initTitle() { ... } ... public void initForMode(final ActionMode mode) { ... }}
setSplitToolbar();
判断此ActionBar
是否需要split
;跟ActionBarView
的方法类似。
setCustomView();
移除里面的View
,自定义View
放置到ActionBarView
上;initTitle();
这个是初始化ActionBar
的title
的方法。使用LayoutInflater.inflate
方法将title
布局加载进来,并且初始化其中的TitleView
、SubtitleView
;initForMode()
;根据ActionMode
初始化ActionBar
;包括MenuView
、SplitView
;
好了,ActionBarContextView
;的主要方法也就完了。
最后我们通过图,来加深下印象,本来想自己画,但是看到网上有个好图就直接拿来了~
参考文章:Android ActionBar的源代码分析(二)这里的几个图都是这篇文章里的。
好了,setContentView,大致就分析完了,接下来我们继续分LayoutInflater,分析其时如何加载xml文件的。
- Android中View的相关知识(5)
- android中view坐标相关的知识
- Android中View的相关知识(3)
- Android中View的相关知识(4)
- Android中View的相关知识(6)
- Android中View的相关知识(7)
- Android中View的相关知识(8)
- 整理View的相关知识
- 自定义view的相关知识
- Android各种知识图(3):View相关
- Android View中onMeasure的相关解析
- Android中编写Service相关的知识
- android setSelected及view相关知识
- Android基础知识梳理之View相关知识
- Android View相关核心知识问答
- android 相关知识总结(不断更新中....)
- android中自定义view涉及到的绘制知识
- 关于Android中View滑动知识的一点个人理解
- EJB3.0+WebLogic操作文档
- DonMin-2017-6-1-day06
- iOS UI学习之路01
- 多线程知识巩固(三)
- Gradle发布项目到JCenter仓库
- Android中View的相关知识(5)
- stm32f103zet6时钟
- Redmine的安装、总结和心得
- https原理
- 谈谈final, finally, finalize的区别
- 学习习近平总书记系列重要讲话精神
- uboot Makefile 分析
- c#连接mysql
- java编译期和运行期优化