当前位置: 首页 > news >正文

Android:主题切换

一.概述

正在开发的应用做了一版新UI,原打算将新版UI按项目名做成资源包,再在build.gradle里productFlavors{ }多渠道打包实现

但被告知新旧两个项目共用一个分支,那就做成两个主题(Theme1/Theme2)来适配了

如果只是变更UI,做成多主题来适配不同项目也是比较合适的方式

一.Android App实现多主题的主要有如下几种:

  1. 从服务器下载或提前放置不同主题资源包到设备指定目录,在代码里引用主题资源
  2. 定义不同的<style>、使用Android的setTheme()机制设置不同主题
  3. 将主题资源做成APK,使用远程Context的方式访问Apk中的主题资源。

第1、第3种方法的实现原理,是用户从服务器下载 或 提前放置主题资源,然后在代码中进行引用

第2种方法是接下来先要讲的, 也是这次新旧UI开发适配完成的方式。

第2种讲完后,也会同步介绍第1、第3种方法

除了这三种常用的方式外,还有一种通过"修改framework中Resources类获取资源的流程,将资源重定向到主题包中"的实现方式,这种方式暂不做讨论

二.setTheme()实现主题切换

2.1 定义属性(attr)

App的UI由各种布局文件实现,布局文件中要定义Android各类UI属性(drawable、colors、mipmap、dimension、string......)引用UI资源。

先将Theme1、Theme2各布局文件中都有定义但需要引用不同值的UI属性挑出来,按照不同类型在/values/attrs.xml中进行定义:

<?xml version="1.0" encoding="utf-8"?>  
<resources>  <attr name="ColorAttrName" format="color" />  <attr name="integerAttrName" format="integer" />  <attr name="booleanAttrName" format="boolean" />  <attr name="dimensionAttrName" format="dimension" />  <item name="floatAttrName" format="dimension" />  <attr name="stringAttrName" format="string" />  <attr name="referenceAttrName" format="reference" />  
</resources>  

reference主要对应drawable、mipmap资源,其他的看字面意思

2.2 定义主题(Theme1/Theme2)

/values/style.xml中定义Theme1、Theme2

<style name="ThemeBlack" parent="@android:style/Theme.Black">  <item name="colorAttrName">#FF00FF00</item>  <item name="integerAttrName">33</item>  <item name="booleanAttrName">true</item>  <item name="dimensionAttrName">76dp</item><item name="floatAttrName">0.35</item>    <item name="stringAttrName">@string/hello_world</item>  <item name="referenceAttrName">@drawable/hand</item>  
</style><style name="ThemeLight" parent="@android:style/Theme.Light">  <item name="colorAttrName">#FFFFFF00</item>  <item name="integerValue">55</item>  <item name="booleanAttrName">false</item>  <item name="dimensionValue">76px</item>  <item name="floatAttrName">0.15</item>    <item name="stringAttrName">@string/action_settings</item>  <item name="referenceAttrName">@drawable/ic_launcher</item>  
</style>

各属性的具体值可以在Theme定义时配置,但是最好定义在各自的xml配置文件中(color.xml、string.xml、dimens.xml.....),然后在Theme定义时"@类型/..."格式引用

Theme中如果string类型不是引用而是字符串,在布局文件中使用正常,但代码里获取会有问题

2.3 布局文件中引用属性

使用过程也很简单,原本布局文件中引用UI属性的方式如下:

android:color="@color/colorAttrName"
android:duration="@integer/integerValue"
android:adjustViewBounds="@bool/booleanAttrName" 
android:layout_height="@dimen/dimensionValue"
android:text="@string/stringAttrName"
android:background="@drawable/referenceAttrName"

现在改为这样进行引用:

android:color="?attr/colorAttrName"
android:duration="?attr/integerValue"
android:adjustViewBounds="?attr/booleanAttrName" 
android:layout_height="?attr/dimensionValue"
android:text="?attr/stringAttrName"
android:background="?attr/referenceAttrName"

float比较特殊,一般它会在代码中被引用(后面会讲到),配置文件中多在dimens.xml中定义变量

2.4 代码中切换主题

要配置的都配置好了,需要注意的是:

  • 最好写一个BaseActivity,其他的Activitiy都继承至它
  • 主题设置需要在setContentView()之前

接下来就在代码中进行主题切换:

package com.android.example.ui;import android.os.Bundle;import com.android.example.R;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (setThemeBlack) {setTheme(R.style.ThemeBlack);} else {setTheme(R.style.ThemeLight);}}
}

主题设置写在BaseActivity的onCreate()函数中,它会在其他所有继承至它的Activity的onCreate()之前运行。

2.5 代码中引用属性

如果要在代码中引用 integerValue、floatAttrName、booleanAttrName,使用Context.obtainStyledAttributes()就可以了

package com.android.example.ui;import android.os.Bundle;import com.android.example.R;import android.content.res.TypedArray;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (setThemeBlack) {setTheme(R.style.ThemeBlack);} else {setTheme(R.style.ThemeLight);}TypedArray tyar = obtainStyledAttributes(new int[]{R.attr.colorValue,R.attr.integerValue,R.attr.booleanValue,R.attr.dimensionValue,R.attr.floatValue,R.attr.stringValue,R.attr.referenceValue});int colorArrtValue = tyar.getColor(0, Color.BLACK);int integerArrtValue = tyar.getInt(1, Integer.MAX_VALUE);boolean booleanArrtValue = tyar.getBoolean(2, false);float dimensionArrtValue = tyar.getDimensionPixelSize(3, 66);float floatArrtValue = tyar.getFloat(4, 99.99f);String stringArrtValue = tyar.getString(5);Drawable drawableArrtValue = tyar.getDrawable(6);}
}

到此,通过setTheme()切换主题方式就讲述完毕了 

这种切换主题方式的优点是:不需要修改太多代码,大部分修改只要针对布局文件就行。

弊端就是:主题只能内置配置好,一旦程序发布后,应用支持的主题类型就固定了,要想增加更多主题,只能发布新的版本。

如果想要动态配置主题,可以使用前文中提到过第1、第3种主题切换方式。

就是接下来要讲的内容了

三.主题资源打包成Apk进行切换

Apk主题切换和第1种将主题包整体下载或提前放置的方案很像。

共同点是:都需要在代码中动态设置图片、文字、颜色等UI信息。

区别是:第1种方法需要自行编写资源解析的方法。而Apk主题切换,可以使用Android自带Api

APK主题方案的基本思路是:

在Android中,所有的资源都是基于包的。资源以id进行标识,在同一个应用中,每个资源都有唯一标识。但在不同的应用中,可以有相同的id。

因此,只要获取到了其他应用的Context对象,就可以通过它的 getRsources() 获取到其绑定的资源对象。

然后,就可以使用 Resources 的 getXXX 方法获取字符串、颜色、dimension、图片等。

要想获取其他应用的Context对象,Android已经为我们提供好了接口:

android.content.ContextWrapper.createPackageContext(String packageName, int flags)

package com.android.example.ui;import android.os.Bundle;
import androidx.annotation.Nullable;public class MainActivity extends BaseActivity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView text = (TextView) findViewById(R.id.remoteText);TextView color = (TextView) findViewById(R.id.remoteColor);ImageView image = (ImageView) findViewById(R.id.remote_image);try {//主题资源Apk包名String remotePackage = "com.xxx.themepackage";//主题资源Apk ContextContext remoteContext = createPackageContext(remotePackage,CONTEXT_IGNORE_SECURITY);//主题资源Apk ResourcesResources remoteResources = remoteContext.getResources();text.setText(remoteResources.getText(remoteResources.getIdentifier("application_name", "string", remotePackage)));color.setTextColor(remoteResources.getColor(remoteResources.getIdentifier("delete_target_hover_tint", "color", remotePackage)));image.setImageDrawable(remoteResources.getDrawable(remoteResources.getIdentifier("ic_launcher_home", "drawable", remotePackage)));} catch (NameNotFoundException e) {e.printStackTrace();}}
}

四.综述

3.高级应用

内置主题实现简单、配置方便,但可扩展性不强。

Apk切换主题扩展性高,但要在代码里设置所有可变资源,一旦界面布局改变,需要较长时间进行代码改写。

实际运用中,可以将以上两种结合起来使用:

涉及到界面风格,如整体色调、不同的文字颜色,使用内置主题。图片资源则在APK主题包中提供。

相关文章:

Android:主题切换

一.概述 正在开发的应用做了一版新UI&#xff0c;原打算将新版UI按项目名做成资源包&#xff0c;再在build.gradle里productFlavors{ }多渠道打包实现 但被告知新旧两个项目共用一个分支&#xff0c;那就做成两个主题(Theme1/Theme2)来适配了 如果只是变更UI&#xff0c;做成…...

terminalworks ASP.NET Core PDF 浏览器-Crack

ASP.NET Core 的 PDF 查看器 terminalworks在 ASP.NET Core 网页或应用程序中添加可靠的 PDF 查看器的简单方法。 我们的 Web PDF 查看器基于经过验证和测试的 Mozilla PdfJS 解决方案&#xff0c;该解决方案在 Firefox 中用作默认 PDF 查看器。我们专门设计了我们的查看器&…...

Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列

目录 58. 最后一个单词的长度 Length of Last Word &#x1f31f; 59. 螺旋矩阵 II Spiral Matrix II &#x1f31f;&#x1f31f; 60. 排列序列 Permutation Sequence &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日…...

短视频矩阵源码如何做应用编程?

短视频矩阵源码&#xff0c; 短视频矩阵系统技术文档&#xff1a; 可以采用电子文档或者纸质文档的形式交付&#xff0c;具体取决于需求方的要求。电子文档可以通过电子邮件、远程指导交付云存储等方式进行传输、 短视频矩阵{seo}源码是指将抖音平台上的视频资源进行筛选、排…...

【运维知识进阶篇】Ansible实现一套完整LNMP架构

前面介绍了PlayBook怎么写服务部署&#xff0c;把服务部署上后&#xff0c;我们来用Ansible来部署项目&#xff0c;实现一套完整的LNMP架构。我们部署wordpress、wecenter、phpshe、phpmyadmin这四个项目。将其所有的剧本都写入lnmp.yml中&#xff0c;相关备份数据都放入root/a…...

Spring Boot 自动配置一篇概览

一、什么是自动配置 bean 自动配置类通过添加 AutoConfiguration 注解实现。 因为 AutoConfiguration 注解本身是以 Configuration 注解的&#xff0c;所以自动配置类可以算是一个标准的基于 Configuration 注解的类。 Conditional 注解可以用于声明自动配置启用条件&#x…...

深入理解设计原则之接口隔离原则(ISP)【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 LSP&#xff1a;接口隔离原则 系列文章目录1、接口隔离原则的定义和解读2、案例解读3、如何判断一个接口是否符合接口隔离原则&#xff1f;小结 1、接口隔离原则的定义和…...

IMX6ULL裸机篇之I2C实验主控代码说明二

一. I2C实验 I2C实验内容&#xff1a; 学习如何使用 I.MX6U 的 I2C 接口来驱动 AP3216C&#xff0c;读取 AP3216C 的传感器数据。 I2C读写数据时序图&#xff1a; I2C写数据时序图如下&#xff1a; I2C读数据时序图如下&#xff1a; 二. I2C主控读写时序 1. 读数据与写数…...

【计算机组成原理与体系结构】数据的表示与运算

目录 一、进位计数制 二、信息编码 三、定点数数据表示 四、校验码 五、定点数补码加减运算 六、标志位的生成 七、定点数的移位运算 八、定点数的乘除运算 九、浮点数的表示 十、浮点数的运算 一、进位计数制 整数部分&#xff1a; 二进制、八进制、十六进制 --…...

如何入门编程

随着信息技术的快速发展&#xff0c;编程已经成为一个越来越重要的技能。那么&#xff0c;我们该如何入门编程呢&#xff1f;欢迎大家积极讨论 一、自学编程需要注意什么&#xff1f; 对于我个人的理解&#xff0c;其实自学编程最重要的就是兴趣。你得培养编程兴趣。 所以在学…...

SQL中CONVERT转化日期函数的使用方法

SQL中CONVERT转化日期函数的使用方法 SQL中CONVERT函数最常用的是使用convert转化长日期为短日期&#xff0c;如果只要取yyyy-mm-dd格式时间, 就可以用convert(nvarchar(10),field,120) 120 是格式代码, nvarchar(10) 是指取出前10位字符. 例如 SELECT CONVERT(nvarchar(10),…...

SpringBoot2-核心技术(一)

SpringBoot2-核心技术&#xff08;一&#xff09; 了解SpringBoot配置文件的使用 文章目录 SpringBoot2-核心技术&#xff08;一&#xff09;了解SpringBoot配置文件的使用一、文件类型1. properties2. yaml 二、yaml的基本使用1. 基本语法2. 数据类型2.1 字面量 2.2 对象2.3 …...

mac host学习

参考&#xff1a; SSH中known_hosts文件作用和常见问题及解决方法 https://blog.csdn.net/luduoyuan/article/details/130070120在 Mac 上更改 DNS 设置 https://support.apple.com/zh-cn/guide/mac-help/mh14127/mac mac中有时候你输入的域名&#xff0c;但会跳转到与期望ip不…...

Java之~指定String日期时间,5分钟一截取时间

// 截取5分钟时间Testpublic void timeCutForDay() throws ParseException {String startTime "2023-03-28 09:16:03";String endTime "2023-03-31 23:59:59";SimpleDateFormat dateFormat new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");D…...

【chatGPT4结对编程】chatGPT4教我做图像分类

开始接触深度学习 大语言模型火了之后&#xff0c;我也想过是否要加入深度学习的行业当中来&#xff0c;一开始的想法就是AI大模型肯定会被各大厂垄断&#xff0c;我们作为普通应用型软件工程师直接调用api就完事&#xff0c;另外对自己的学历也自卑(刚刚够线的二本&#xff0…...

Different romantic

001 他暗恋上我们班上的一个女生。 He has a crush on a girl in our class. crush n. 迷恋 have a crush on (someone) 暗恋&#xff08;某人&#xff09; crush 也可以指“暗恋的对象”。例如&#xff0c;“他在大学曾经暗恋过两个人”&#xff0c;英语就是He had two crushe…...

learn C++ NO.7——C/C++内存管理

引言 现在是5月30日的正午&#xff0c;图书馆里空空的&#xff0c;也许是大家都在午休&#xff0c;也许是现在37摄氏度的气温。穿着球衣的我已经汗流浃背&#xff0c;今天热火战胜了凯尔特人&#xff0c;闯入决赛。以下克上的勇气也激励着我&#xff0c;在省内垫底的大学中&am…...

SDUT数据库原理——第十章作业(参考答案)

1. 简述使用检查点方法进行数据恢复的一般步骤。 答: (1)使用检查点方法进行数据恢复,首先从重新开始文件(见P302页图10.3)中找到最后一个检查点记录在日志文件中的地址,由该地址在日志文件中找到最后一个检查点记录。 (2)由该检查点记录得到检查点建立时刻所有正在…...

My Note of Diffusion Models

Diffusion Models Links: https://theaisummer.com/diffusion-models/ Markovian Hierachical VAE rvs: data: x 0 x_{0} x0​,representation: x T x_{T} xT​ ( p ( x 0 , x 1 , ⋯ , x T ) , q ( x 1 , ⋯ , x T ∣ x 0 ) ) (p(x_0,x_1,\cdots,x_T),q(x_1,\cdots,x_{T…...

【P37】JMeter 仅一次控制器(Once Only Controller)

文章目录 一、仅一次控制器&#xff08;Once Only Controller&#xff09;参数说明二、测试计划设计2.1、测试计划一2.1、测试计划二 一、仅一次控制器&#xff08;Once Only Controller&#xff09;参数说明 可以让控制器内部的逻辑只执行一次&#xff1b;单次的范围是针对某…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...