IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

Android夜间模式实现

开源实验室 2016-03-22 22:36:06 累计浏览 2,126 次
本机暂存

摘要


最近在做一个Android夜间模式的功能,又重新研究了一下Theme机制。贯彻我的风格,以解决问题为目标,写了个小Demo,简单了实现了切换夜间模式,为大家讲解。

最近在做一个Android夜间模式的功能,又重新研究了一下Theme机制。贯彻我的风格,以解决问题为目标,写了个小Demo,简单了实现了切换夜间模式,为大家讲解。
在Activity中有一个方法叫setTheme(),可以设置Activity的Theme,当然Application类中也有相同的方法,也可以在Application中设置当前应用的Theme。就好像我们可以在Manifest文件中通过android:theme=“”来设置主题一样。

创建属性名

在工程目录res/values/下新建一个xml文件,名字可以自定义,这里我的叫theme_attr.xml 内容如下:

<?xml version="1.0" encoding="utf-8"?>
    <resources>
        <attr name="text_bg" format="reference|color"/>
        <attr name="bottom_bg" format="reference|color"/>
    </resources>


其中text_bg和bottom_bg就是我们定义的两个属性名,后面的format是指的这个属性名的类型,这里我是用referencecolor表示既可以是一个引用,也可以是一个argb颜色值。除了这些你还可以选择int,boolan,string等数据类型。

定义资源样式

创建完属性名后就需要创建主题样式了。依旧在res/values/下新建一个xml文件,或者也可以在原style.xml中写,是一样的。这里为了项目结构清晰,就单独写一个文件叫theme_dark.xml 我们需要在这里定义步骤一中定义的各属性名在当前主题下的值。

<resources>
        <!-- Base application theme. -->
        <style name="DarkTheme" parent="@android:style/Theme">
            <item name="text_bg">@drawable/selector_text_bg_dark</item>
            <item name="bottom_bg">@drawable/bg_bottombar_dark</item>
        </style>
    </resources>


需要注意的是,我们自己定义的style必须直接或间接继承系统的Theme,否则很多系统主题找不到就会报错。
还有一点,我们声明了两个属性,这里一定要记得都把值定义了,如果不定义也不会错。但是如果在代码中引用了相应的属性,而这个主题没有定义这个属性的值会运行出错的。
这里可以看到因为上面我属性类型定义了引用或颜色,所以这里的值我既可以传@drawable类型的引用也可以直接赋值一个#ff00ff这样的颜色值。

布局中使用

布局文件中使用我们自定义的文件时,需要添加一个问号来表示引用。例如

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/login_btn"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="?text_bg"android:text="登录"/></LinearLayout>


这样就表示我们的登录按钮的背景使用的是前面定义的属性名text_bg在当前主题下的值,也就是我们步骤二中定义的@drawable/selector_text_bg_dark这张图片(其实是一个选择器了)

代码中使用

以一个最简单的例子来说明了,需要注意的是一定要在Activity的setContentView调用之前调用setTheme()方法。网上有很多介绍都说的是在super之前,其实这种说法并不准确。当我们动态切换主题时,例如点击某个按钮,切换主题,这个时候需要再次手动调用setContentView()方法,并重新调用控件初始化以及监听器设置。但是这里告诉你一种简单方法:直接手动调用recreate()方法,再次创建视图就可以了。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">
          <Button
            android:id="@+id/login_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?text_bg"
            android:text="登录"/>
    </LinearLayout>


同分类推荐文章

  1. 「置顶」我做了什么 (2026-05-05 12:13:28)
  2. 万字长文推演:手机不再从 App 开始,Agent OS 如何接管任务入口 (2026-04-28 14:57:22)
  3. Android Perfetto 系列 10 - Binder 调度与锁竞争 (2025-11-16 15:33:30)

查看更多 移动开发 文章 →

建议继续学习

  1. 情绪版(Mood board)操作流程的新思考 (累计阅读 41,756)
  2. android 开发入门 (累计阅读 19,530)
  3. 【社会化设计】自我(self)部分――欢迎区(welcome area) (累计阅读 16,831)
  4. Android 连接SSID隐藏网络以及 LEAP 认证的方法 (累计阅读 9,539)
  5. 让安卓手机通过代理翻墙的方法 (累计阅读 9,117)
  6. 手机产品设计方向 (累计阅读 7,954)
  7. App的成本 (累计阅读 7,584)
  8. 用色彩打造专业的视觉效果 (累计阅读 7,234)
  9. 实时监控Android设备网络封包 (累计阅读 6,558)
  10. Eclipse开发Android应用程序入门:重装上阵 (累计阅读 6,463)