聊聊Android Theme的那些事

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:22   2025   0

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会有几个选择:

platform version list

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

2.2 它们有什么区别呢?

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

Theme diff

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

2.3 只有这些根主题吗?

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

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

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

theme construction

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

  • TextAppeareance: 定义字体样式。

  • Theme: 定义Dialog和Application的样式。

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

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

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

TextAppearance Theme

同样的Theme系列:

Theme Theme

ThemeOverlay系列:

ThemeOverlay Theme

Widget系列:

Widget Theme

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

3 自定义样式

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

origin

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上会有个版本选择:

show version list

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

found out 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文件去看,一目了然:

r.java

源码之下,没有秘密

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

// after set support action bar
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});

转载于:https://my.oschina.net/ClaireChris/blog/774605

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP