您的位置:首页 > 移动开发 > Android开发

聊聊Android Theme的那些事

2016-10-24 00:00 155 查看

1. 概述

    话说Android里面的主题真是琳琅满目,虽然平时开发时我们都是固定,约定成熟的使用某个主题,例如官方推荐的AppComat系列,但是Android有多少主题,它们之间有什么联系和区别很少人去认真探究。我本人开发时都是直接使用Android Studio生成的主题,或者是继承至它。Holo主题基本没有使用过,似乎是一个比较老的主题,比我早接触Android的前辈们应该比较熟悉。Material主题就属于比较新的主题。还有呢?

2. 一些主要的根主题以及它的继承结构

    这里我使用了“根主题”的说法,因为大多数主题都是继承至某个主题,追根究底,会找到几个没有parent的根主题。我们来看看这几个根主题:

Theme:API 10及其以下的默认主题。

Theme.Holo:API 11 - 13的默认主题,

Theme.Material:API 21及其以上。

2.1 如何追溯到这些Theme?

    你可以随便新建一个Theme,parent继承至
Theme.AppCompat
,按住
Ctrl
(在Mac上是
Command
)点击parent主题,这样一直追溯到
Platform.AppComat
会有几个选择:



到这里,Theme的继承就区别开来了,
/values.xml
最终会继承至
Theme
/values-v11.xml
/values-v14.xml
最终会继承至
Theme.Holo
,而
/values-v21.xml
会继承至
Theme.Material
。所以说,一般我们选择主题选择继承至
AppCompat
系列的主题就可以了(至少现在是如此),
AppCompat
已经做好适配工作了。

2.2 它们有什么区别呢?

    据我所对比观察,它们的参数基本上相同:



双方有些细微的增缺,只有值大不一样,但这并不影响什么,我们必要的时候直接去所关心的Theme那里了解一下目标参数。一个主题规范严格的app,风格的定义应该在App Theme上就得到了统一,这些根主题的参数给了我们修改,参考的依据,了解这些参数是很有必要的。

2.3 只有这些根主题吗?

    当然,Android系统如此庞杂,远远不止这些根主题,上述3个根主题所在的xml文件里定义了很多根主题,适当了解一下会有好处。

2.4 如此多的子主题,我们该如何抉择?看看它的继承结构。

    我先贴上一张自己总结的图:



    我以
AppCompat
系列的主题为例,图中并没有将所有主题都收拢进去,毕竟太多了。图中枝节点的依据是这样子:例如
Base.TextAppearance.AppCompat.Widget.Actionbar.Subtitle.Inverse
这个style,已
.
为分割线,
Base
TextAppearance
...为节点作成的结构图。从图中可以很直观的得出结论:主题分为
TextAppearance
Theme
ThemeOverlay
Widget
4种。

TextAppeareance: 定义字体样式。

Theme: 定义Dialog和Application的样式。

ThemeOverlay: 定义悬浮层的样式,例如点击ActionBar上的更多或者下拉菜单弹出的悬浮界面的样式。

Widget:顾名思义,定义
Button
之类的组件的样式。

如果你想使用某个字体主题或者自定义,你可以使用或者继承TextAppearance系列:



同样的Theme系列:



ThemeOverlay系列:



Widget系列:



Android的Style命名已经极大的便利我们使用,我们唯一要做的事就是根据业务需求了解某个主题的参数和值,并且在必要的时候复写它。

3 自定义样式

    现在用实际行动来验证我们的猜想。我新建了一个Activity,它是这样子:



Activity
代码:

public class ActionBarActivity extends AppCompatActivity {

@Bind(R.id.toolbar) Toolbar mToolbar;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_action_bar);
ButterKnife.bind(this);

mToolbar.setTitle("Thanatosx");
mToolbar.setSubtitle("Widgets");

setSupportActionBar(mToolbar);

ActionBar mActionBar = getSupportActionBar();
if (mActionBar != null){
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setHomeButtonEnabled(false);
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menus, menu);
return super.onCreateOptionsMenu(menu);
}

}

Layout布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#80123456"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</LinearLayout>

以及Theme主题:

<style name="AppTheme" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
</style>

现在我们想要通过修改Theme来改变Toolbar的样式达到以下效果:

改变返回图标

改变Title和Subtitle的字体大小和颜色

改变more icon的颜色

首先,第一个问题是:去哪里修改?前面说到,Theme主题基本可以定义一个Application的大部分地方的样式,我们需要去搜索一下父主题是否有这样的定义,从
Theme.AppCompat.Light
这个主题开始往上追溯,在
Base.Theme.AppCompat.Light
上会有个版本选择:



这个无所谓,选择低版本的就可以了,低版本都支持的话就不用担心高版本,首先会在
Base.v7.Theme.AppCompat.Light
上发现Toolbar Style的定义:



那么,我们就可以复写这个属性,自定义我们的Toolbar Style了,同样的,有个
actionOverflowButtonStyle
属性,它就是定义more icon button的属性了。

修改后的Theme:

<style name="AppTheme" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="actionOverflowButtonStyle">@style/AppWidget.ActionButton.Overflow</item>
<item name="toolbarStyle">@style/AppTheme.Toolbar</item>
</style>

<style name="AppTheme.Toolbar" parent="Widget.AppCompat.Toolbar">
<item name="android:minHeight">50dp</item>
<item name="titleTextAppearance">@style/AppTextAppearance.Widget.Actionbar.Title</item>
<item name="subtitleTextAppearance">@style/AppTextAppearance.Widget.Actionbar.Subtitle</item>
<item name="navigationIcon">@mipmap/ic_back</item>
<item name="android:background">?attr/colorPrimary</item>
</style>

<style name="AppTextAppearance.Widget.Actionbar.Title" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textSize">14sp</item>
<item name="android:textColor">#FFF</item>
</style>

<style name="AppTextAppearance.Widget.Actionbar.Subtitle" parent="TextAppearance.Widget.AppCompat.Toolbar.Subtitle">
<item name="android:textSize">12sp</item>
<item name="android:textColor">#FFF</item>
</style>

<style name="AppWidget.ActionButton.Overflow" parent="Widget.AppCompat.ActionButton.Overflow">
<item name="android:src">@mipmap/ic_more</item>
</style>

parent继承至原使用的Style Theme,以此基础上重写自己需要修改的属性,最终效果图:



4 坑

在修改Activity的返回按钮的时候我在
AppTheme
里找到这个属性:
homeAsUpIndicator
,老司机们肯定明白,这就是设置返回按钮的图标,但是无论我如何设置,修改,这个属性没有任何效果!!无奈之下,我去overflowstack上寻找答案,众说纷纭,倒是看到这个属性
navigationIcon
,我在Theme上没看到,在Toolbar的主题上也没有看到,但是当我进入Toolbar的源码,我发现是有这个属性的:



我直接跑去R.java文件去看,一目了然:



源码之下,没有秘密

还有一点,设置
navigationIcon
之后,点击返回按钮没有任何响应了,需要设置Navigation Click Listener

// after set support action bar
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android Theme