子墨庖丁Android的ActionBar源码分析 (一)实例化
如果你从事过Android客户端开发,相信你对ActionBar这套框架并不陌生,或者说你并不了解它,但是你应该时不时的要跟它打交道。抛开ActionBar的实现不说,ActionBar实际上是对Android的TitleBar行为的抽象,这种框架可以适用于这种模式的应用,是对需要的行为视图的抽象。当然或许你也和我一样,对ActionBar的实现效率并不满意,因为你打开它的视图,你会发现它的实现非常的ugly。不过我们庆幸的看到的是,ActionBar在设计的时候就并不是以一个强类型的姿态存在,我们发现它并不是以一个View的方式存在,而跟Fragment一样是一个很单纯的工具类。这种设计正好屏蔽了内部的实现,从而可以让我们对它的实现进行改造。当然ActionBar的改造对我来说并不是文章的重点,如果你对自定义控件已经熟门熟路了,那么相信你阅读完这个系列的文章以后,能更有助于你改造ActionBar。对本章我将从ActionBar生成入口开始讲述。
我们知道我们再定义一个Activity的时候,跟WMS直接挂钩的客户端代理是Window类,当然,我这么说本身不准确。因为Window是间接持有这种代理类,不过这不影响我们对ActionBar的整体理解。对于Window类来说,它跟我们直接打交道是PhoneWindow。我们将调用setContentView的方式来注册我们需要的内部视图,为什么说是内部视图,因为除了我们的视图之外,Window里面还注册有多个的视图装饰。其实这也是装饰模式的一种,甚至很像模板方法。
@Overridepublic 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 HooksetFlags(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的介入,而这种介入你在客户端配置文件中定义的时候,需要转化成为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.ActionBarContainerandroid:id="@+id/action_bar_container"android:layout_width="match_parent"android:layout_height="wrap_content"style="?android:attr/actionBarStyle"><com.android.internal.widget.ActionBarViewandroid:id="@+id/action_bar"android:layout_width="match_parent"android:layout_height="wrap_content"style="?android:attr/actionBarStyle" /><com.android.internal.widget.ActionBarContextViewandroid: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 stylefinal 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:http://weibo.com/1752090185/profile?rightmod=1&wvr=5&mod=personinfo
子墨庖丁Android的ActionBar源码分析 (一)实例化相关推荐
- 子墨庖丁Android的ActionBar源代码分析 (一)实例化
假设你从事过Androidclient开发,相信你对ActionBar这套框架并不陌生,或者说你并不了解它,可是你应该时不时的要跟它打交道.抛开ActionBar的实现不说,ActionBar实际上是 ...
- CTS(11)---android自动化测试CTS源码分析之一
android自动化测试CTS源码分析之一 1, 概述 CTS(Compatibility Test Suite)全名兼容性测试,主要目的就是让Android设备开发商能够开发出兼容性更好的andro ...
- android agps,Android应用开发Android GPS ——AGPS源码分析及配置
本文将带你了解Android应用开发Android GPS --AGPS源码分析及配置,希望本文对大家学Android有所帮助. " Android Framework GPS --AGPS ...
- android gps源码分析,Android编程之Android GPS ——AGPS源码分析及配置
本文主要介绍了Android编程的Android GPS --AGPS源码分析及配置,通过具体的分析以及源码,向大家展示了这些,希望对大家学习Android编程有所帮助. 1:冷启动指令: locat ...
- Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)
1.先熟悉handler方式实现主线程和子线程互相通信方式,子线程和子线程的通信方式 如果不熟悉或者忘记了,请参考我的这篇博客 Android之用Handler实现主线程和子线程互相通信以及子 ...
- android(cm11)状态栏源码分析(一)
版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/50216563 (一):写在前面 最近由于工 ...
- Android 7.0 源码分析项目一期竣工啦
从 Android 入行开始,因为工作需求和解决疑难bug的原因陆陆续续的看过一些源码,但都不成系统,从2016年年底开始,在Github上建了一个Android Open Source Projec ...
- Android之AsyncTask源码分析(第五篇:execute方法只能执行一次的原因)
(注意:本文基于API 28的源码分析,API 29上或其他平台的源码略有不同) 前言 当你调用AsyncTask对象的execute()方法时,突然发生崩溃--内心充满不解:java.lang.Il ...
- Android——RIL 机制源码分析
Android 电话系统框架介绍 在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP.AP与BP之间有两种通信方式: 1. ...
最新文章
- arch更新失败的办法
- MPX2053DP压力传感器简单测量
- linux常用命令之lsof 、netstat、ipcs、ldd
- 傻瓜式Linux之一:系统安装
- linux root登陆ftp,LINUX服务器下用root登录ftp
- ios 开发者账号申请流程 最新
- highcharts如何把图多余的空白页面_零基础如何快速学会WORD基础操作?有秘籍了.........
- window 效率神器:Wox
- android之自定义广播
- android camera fragment,Android Camera 模块分析(三)
- Java项目课程02:系统概述
- 请解释python面向对象中的继承
- java 获取 jsp 内容_JAVA记录-JSP内容
- COMSOL—— LiveLink for MATLAB学习1
- python仓库管理
- 计算机函数公式法计算出总分的式子,excel计算百分比公式的用法
- 尾气冒黑烟是什么问题_汽车排气管冒黑烟,怎么回事?
- win10开机自动有线连接拨号上网
- 云队友丨40岁之前,希望你懂得这5条定律
- 微型计算机显卡必须插在主板的,花小钱办大事 不同型号N卡组建SLI系统
热门文章
- snort-2.9.7.0源码安装过程
- Google断供之下,我们如何杀出一条血路
- C# 发送xml报文到用友U8生成凭证系列四(Biz代码)最终代码
- CSA云安全指南V4.0 D1 D2
- 让你的文字更出色:编辑和校对的有效策略
- Android自定义日期区间选择,类似12306酒店入住的日期选择
- 打印机调用彩色和黑色JAVA,Java:利用接口实现打印机案例(墨盒有彩色和黑白色,纸张有A4纸和B5纸)...
- 基于802.11n物理层的OFDM通信链路simulink仿真,包括FEC编码、插入导频、OFDM成帧、STBC编码
- 微信小程序各种动画轮子链接
- Java 实现简易计算器