假设你从事过Androidclient开发,相信你对ActionBar这套框架并不陌生,或者说你并不了解它,可是你应该时不时的要跟它打交道。抛开ActionBar的实现不说,ActionBar实际上是对Android的TitleBar行为的抽象,这样的框架能够适用于这样的模式的应用,是对须要的行为视图的抽象。当然也许你也和我一样,对ActionBar的实现效率并不惬意。由于你打开它的视图,你会发现它的实现非常的ugly。

只是我们庆幸的看到的是,ActionBar在设计的时候就并非以一个强类型的姿态存在,我们发现它并非以一个View的方式存在,而跟Fragment一样是一个非常单纯的工具类。

这样的设计正好屏蔽了内部的实现,从而能够让我们对它的实现进行改造。当然ActionBar的改造对我来说并非文章的重点,假设你对自己定义控件已经熟门熟路了,那么相信你阅读完这个系列的文章以后,能更有助于你改造ActionBar。对本章我将从ActionBar生成入口開始讲述。

我们知道我们再定义一个Activity的时候,跟WMS直接挂钩的client代理是Window类,当然,我这么说本身不准确。

由于Window是间接持有这样的代理类,只是这不影响我们对ActionBar的总体理解。

对于Window类来说,它跟我们直接打交道是PhoneWindow。我们将调用setContentView的方式来注冊我们须要的内部视图,为什么说是内部视图,由于除了我们的视图之外,Window里面还注冊有多个的视图装饰。事实上这也是装饰模式的一种。甚至非常像模板方法。

@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}

我们发现实际上我们的视图是包括在一个叫做mContentParent的ViewGroup中。

而这个对象的生成是定义在Window类中的protected ViewGroup generateLayout(DecorView decor)方法中。

我们知道对于一个Window视图的影响除了Window.LayoutParams外还有Feature。

Feature对视图的影响并不直接跟WMS打交道。即使跟WMS打交道也是通过WIndow.LayoutParams类控制。也就是说Feature本身就是一种可有可无的小甜点。在生成mContentParent的时候你会常常看到一些属性匹配代码:

int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
if (mIsFloating) {
setLayout(Injector.getFloatingWindowWidth(getContext()), WRAP_CONTENT); // Miui Hook
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
} if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
} if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
requestFeature(FEATURE_ACTION_BAR_OVERLAY);
}

我们知道我们能够制定一个视图的主题集合,而这样的主题集合中能够定制各种的外观參数,还有特征属性。当中一部分要转化成为Window.LayoutParams来跟WMS打交道。

比方:

if (!hasSoftInputMode()) {
params.softInputMode = a.getInt(
com.android.internal.R.styleable.Window_windowSoftInputMode,
params.softInputMode);
}

我们能够看出,实际上对于一个窗体的输入法管理,是须要WMS的介入,而这样的介入你在client配置文件里定义的时候,须要转化成为Window.layoutparams參数的属性,让它来传递给WMS来触发管理。

if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = com.android.internal.R.layout.screen_simple;
}

我们看出,假设你已经定义了ActionBar主题项,那么它将使用screen_simple或者overlay这两种模式的我们仅仅考虑simple方式,我们来看下simple的布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true">
<com.android.internal.widget.ActionBarContainer
android:id="@+id/action_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle">
<com.android.internal.widget.ActionBarView
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle" />
<com.android.internal.widget.ActionBarContextView
android:id="@+id/action_context_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
style="? android:attr/actionModeStyle" />
</com.android.internal.widget.ActionBarContainer>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
<com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarSplitStyle"
android:visibility="gone"
android:gravity="center"/>
</LinearLayout>

我们能够直观的看到这跟我们所熟知的ActionBar布局一致。纵向,ActionBar事实上就是ActionBarContainer。对于ActionBar的解析和布局我们放到后面再讲。

我们看到当我们决定使用哪种布局之后,通过调用:

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

方法获取mContentParent,也就是说我们的视图就是包括在这个ActionBar容器中的Content容器中。

我们回到Activity的setConentView方法。我们在设置完我们的视图以后,它会初始化initActionBar();

我前面已经说过了,ActionBar和Fragment本身不属于AndroidUI系统的一部分,因此须要对它进行初始化。ActionBar的实现类是com.android.internal.app.ActionBarImpl,由于ActionBarImpl针对的是Window,因此不论你是Activity或者是Dialog或者是PopupWindow理论上都能够使用ActionBar。这样的理论实际上也能够说明一点,就是在同一个界面中出现两个ActionBar是合理的。甚至你在同一个Window里面不同的Fragment中实现自己的一套ActionBar也是可行的。由于它并不纳入在WMS的管理中,好吧,有点扯远了,我们继续前文。

public ActionBarImpl(Activity activity) {
mActivity = activity;
Window window = activity.getWindow();
View decor = window.getDecorView();
init(decor);
if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
mContentView = decor.findViewById(android.R.id.content);
}
}

我们看到ActionBarImpl的初始化主要通过init方法实现。

private void init(View decor) {
mContext = decor.getContext();
mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
com.android.internal.R.id.action_bar_overlay_layout);
if (mOverlayLayout != null) {
mOverlayLayout.setActionBar(this);
}
mActionView = (ActionBarView) 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);
mTopVisibilityView = (ViewGroup)decor.findViewById(
com.android.internal.R.id.top_action_bar);
if (mTopVisibilityView == null) {
mTopVisibilityView = mContainerView;
}
mSplitView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.split_action_bar); if (mActionView == null || mContextView == null || mContainerView == null) {
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with a compatible window decor layout");
} mActionView.setContextView(mContextView);
mContextDisplayMode = mActionView.isSplitActionBar() ?
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; // This was initially read from the action bar style
final int current = mActionView.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());
}

主要为了初始化一些视图參数,还有往ActionBarOverlayLayout对象注入一个ActionBar控制回调,当然也就是它本身。但我们也能从代码看出,ActionBar本身每一个内部对象之间耦合度相对较高,互相引用。只是面向ActionBar接口来编程能有效的屏蔽掉这样的低效率。到这里,实际上,对于ActionBar的实例化已经完毕。下一章我们将開始ActionBar视图布局的的讨论。

非子墨:

QQ:1025250620

SINA:

rightmod=1&wvr=5&mod=personinfo">http://weibo.com/1752090185/profile?

rightmod=1&wvr=5&mod=personinfo

子墨庖丁Android的ActionBar源代码分析 (一)实例化的更多相关文章

  1. android(cm11)状态栏源代码分析(一)

    (一):写在前面 近期因为工作须要,须要了解CM11中的有关于StatusBar相关的内容.总的来说,刚開始阅读其源代码的时候,是有点困难,只是通过构建相关代码的脑图和流程图,几天下来.我已经对其源代 ...

  2. Android 中View的绘制机制源代码分析 三

    到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编 ...

  3. Appium Android Bootstrap控制源代码的分析AndroidElement

    通过上一篇文章中<Appium Android Bootstrap源代码分析之简单介绍>我们对bootstrap的定义以及其在appium和uiautomator处于一个什么样的位置有了一 ...

  4. Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...

  5. Android HandlerThread 源代码分析

    HandlerThread 简单介绍: 我们知道Thread线程是一次性消费品,当Thread线程运行完一个耗时的任务之后.线程就会被自己主动销毁了.假设此时我又有一 个耗时任务须要运行,我们不得不又 ...

  6. Android 中View的绘制机制源代码分析 一

    尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差点儿相同半年没有写博客了,一是由于工作比較忙,二是认为没有什么内容值得写, ...

  7. Android 中View的绘制机制源代码分析 二

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要解说 ...

  8. Appium Android Bootstrap源代码分析之启动执行

    通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...

  9. Android系统进程Zygote启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6768304 在Android系统中,所有的应用 ...

随机推荐

  1. 【Javascript Demo】无刷新预览所选择的图片

    1.效果如下,可测试 2.代码如下 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " ...

  2. 【Javascript Demo】遮罩层和弹出层简单实现

    最近纠结于遮罩层和弹出层的实现,终于搞定了个简单的版本.示例和代码如下,点击按钮可以看到效果: 1.示例: 2.代码: <!DOCTYPE html PUBLIC "-//W3C//D ...

  3. Drupal Working with nodes, content types and fields

    一个大概的总结,便于对接下来的学习进行理解和运行 在使用Drupal过程中.站点中的内容的不论什么一个部分都是一个节点(node),而每一个节点中又包括了一些默认的字段(fields). 值得说明的是 ...

  4. Fusioncharts的导出图片訪问官网问题

    Fusioncharts3.5使用自带的导出功能,须要訪问官网 问题描写叙述:使用fusioncharts自带的exportchart方法来导出图片的时候.要訪问export.api3.fusionc ...

  5. ubuntu Server 设置主机静态 ip地址

    ubuntu Server 设置主机静态 ip地址 1:先输入 ifconfig 查看当前网络配置 2:然后关闭 eth0 网卡 sudo ifdown eth0 3:配置静态ip sudo vim ...

  6. Linux安装 微信开发者工具(deepin linux ubt)

    一.环境:: deepin linux15.4.1 二.安装过程: 2.1 安装wine sudo apt-get install wine 2.2 安装nwjs-sdk 2.2.1 下载linux版 ...

  7. ViewPager切换动画效果改动

    比方我们点击向右button,希望左边的view移动过来,有个平移效果,可是用系统默认的ViewPager切换的时候,会一闪而过. 这是为什么呢? 由于viewpager外面事实上有个scrollvi ...

  8. jstl foreach 取index

    <c:forEach var="myAccountInfo" items="${myAccountInfos}" varStatus="inde ...

  9. openerp many2many

    many2many (0,0,{values}) 根据values里面的信息新建一个记录. (1,ID,{values})更新id=ID的记录(写入values里面的数据) (2,ID) 删除id=I ...

  10. 【Linux】echo命令

    用途 echo是用于终端打印的基本命令 说明 只需要使用带双引号的文本,结合echo命令就可以将文本打印在终端. [root@localhost test]# echo "Hello Wor ...