文档章节

聊聊Android Theme的那些事

thanatosx
 thanatosx
发布于 2016/10/24 10:21
字数 1621
阅读 51
收藏 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();
    }
});

© 著作权归作者所有

thanatosx

thanatosx

粉丝 69
博文 13
码字总数 17106
作品 1
深圳
程序员
私信 提问
Android 用户界面---样式和主题(Styles and Themes)(二)

样式属性 理解了样式是如何定义的之后,就需要学习元素都定义了那些有效的样式属性类型。你可能已经熟悉了像layout_width和textColor属性,但是还有更多的可以使用的样式属性。 查找应用于指...

长平狐
2012/10/16
215
0
Android中Style和Theme的使用总结

越来越多互联网企业都在Android平台上部署其客户端,为了提升用户体验,这些客户端都做得布局合理而且美观.......Android的Style设计就是提升用户体验的关键之一。Android上的Style分为了两个...

紫地瓜
2013/02/05
3K
0
Android总结之style(样式)和Theme(主题)

style(样式) style(样式)是针对窗体元素级别的,改变指定控件或者Layout的样式。 抽取一些共同的属性写到style,可以省略大量重复的属性代码。 创建步骤: 在res/values目录下新建一个名叫s...

天王盖地虎626
01/13
41
0
在Eclipse中设置Layout的Theme后,在哪里记录了此设置?

在添加layout时,修改了theme,layout发生的变化,但是修改后的theme记录在哪里呢? 1. 下图是新建的layout,默认的主题是AppTheme 2. 为了不显示title,于是将主题改为Theme.Black.NoTitle...

feifeiliao
2014/07/31
2K
2
2017 我用 5 个月分享了 98 篇优秀博文

对上半年所分享的文章进行一个整理,很多读者当时忘记了收藏,以致于查找一篇历史文章很费劲,因此在这里顺便做下记录。目前就分下下面几个大类,没有更多细分,已基本可以查找了。 如果觉得...

code小生
2018/10/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部