Android应用中动态更改主题的实现

在android应用程序中我们可能需要切换模式,如晚上切换到夜间模式便于阅读等。本文参考了网上的一些资料,并结合实例,实现了动态更改主题的效果。

Android中实现theme主题可以使用在activity中使用setTheme(int)的方法,SDK中对此方法的说明为:

//Set the base theme for this context. Note that this should be called before any views are instantiated in the Context (for example before calling android.app.Activity.setContentView or android.view.LayoutInflater.inflate).
//需要在setcontentview函数或者inflate函数之前使用。

效果图如下:

  

实现步骤:

首先需要定义一个属性,此属性用于赋值给控件的属性,相当于控件属性值的“变量”。

在attrs.xml中,定义三个属性,属性的format均为reference|color

<resources>

    <attr name="button_bg" format="reference|color" />
    <attr name="activity_bg" format="reference|color" />
    <attr name="text_cl" format="reference|color" />

</resources>

接下来,在styles.xml中,编写自定义的Theme

<style name="AppBaseTheme" parent="android:Theme.Light">
    </style>

    <style name="AppTheme" parent="AppBaseTheme">
        <item name="text_cl">#ffffff</item>
        <item name="button_bg">#000000</item>
        <item name="activity_bg">#ffffff</item>
    </style>

    <style name="DarkTheme" parent="AppBaseTheme">
        <item name="text_cl">#000000</item>
        <item name="button_bg">#ffffff</item>
        <item name="activity_bg">#000000</item>
</style>

选择一种模式作为程序的默认theme,注意:由于我是在layout布局文件中定义的view的样式,因此,为了保证theme切换时不会出现找不到资源的问题,因此需要在每一种用到的自定义theme中,都加上item。这里的item如text_cl和view的textColor属性的format是一致的。

Android manifest文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testandroidsettheme"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:name="com.example.testandroidsettheme.app.MyApp"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.testandroidsettheme.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我将android:theme="@style/AppTheme"作为默认的样式。

主界面layout布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?activity_bg"
    android:gravity="center"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="?button_bg"
        android:textColor="?text_cl"
        android:text="set theme" />

</LinearLayout>

在布局文件中,button的background属性采用的是当前theme下的button_bg的属性值,外部的linearlayout采用的是当前theme下的activity_bg的属性值,在填写此属性值时,需要在前面添加”?”,表示这是一个style中的变量。

在需要切换显示不同theme的activity中,一些博客中在button点击事件中使用

setTheme(int);

recreate();

的方式,我发现此种方式无法实现theme的切换,因为recreate()方法会重新创建此activity,之前的setTheme()无效。我的实现方式如下:

public class MainActivity extends Activity {

    public Button button0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApp app = (MyApp)MainActivity.this.getApplication();
        if(app.theme == 0){
            //使用默认主题
        }else{
            //使用自定义的主题
            setTheme(app.theme);
        }
        setContentView(R.layout.activity_main);

        button0 = (Button) this.findViewById(R.id.button0);
        button0.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyApp app = (MyApp)MainActivity.this.getApplication();
                app.theme = R.style.DarkTheme;
                recreate();
            }
        });
    }
}

public class MyApp extends Application{
    public int theme = 0;
}

在此activityoncreate()中的setContentView()方法调用之前,判断当前的theme,并调用setTheme(),实现改变theme的效果。

注意:这种方法实现切换theme不是很友好,因为在activity重新创建时,可能会有闪屏的现象。比较好的解决方案如知乎客户端采用的是截屏,并渐隐图片的过度方式,具体的实现还有待学习。

参考资料:http://www.kymjs.com/code/2015/05/26/01/

时间: 2024-10-03 02:44:12

Android应用中动态更改主题的实现的相关文章

在带(继承)TextView的控件中,在代码中动态更改TextView的文字颜色

今天由于公司项目需求,须要实现一种类似tab的选项卡,当时直接想到的就是使用RadioGroup和RadioButton来实现. 这种方法全然没问题.可是在后来的开发过程中,却遇到了一些困扰非常久的小困难.大概需求是:在代码中.动态的获取tab的个数,然后初始化RadioGroup,每个tab相应一个RadioButton,即加入一个tab就要向RadioGroup中add一个RadioButton,然后在button选中时要更改文字颜色.由于是动态加入,所以无法在xml中配置了RadioBut

Android代码中动态设置图片的大小(自动缩放),位置

项目中需要用到在代码中动态调整图片的位置和设置图片大小,能自动缩放图片,用ImageView控件,具体做法如下: 1.布局文件 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

VS2013中如何更改主题颜色(深色)和恢复默认的窗口布局

1.通常情况下,我们会根据个人爱好更改VS2013的主题颜色,一开始我喜欢白色,后来我偏爱深色. 依次选择:工具->选项->常规->主题->深色->确定,ok 2.我们在编辑时最容易把窗口布局搞乱,此时,我们需要重置窗口布局. 依次选择:窗口->重置窗口布局->确定,ok

[Android] 代码中动态设置shape

TextView textView = new TextView(this); GradientDrawable drawable = new GradientDrawable(); drawable.setCornerRadius(5); drawable.setStroke(1, Color.parseColor("#cccccc")); drawable.setColor(Color.parseColor("#eeeeee")); textView.setBa

Android代码中更改TextView颜色

项目中,需要在代码中动态更改TextView的颜色,原先使用如下: text.setTextColor(R.color.black); 为生效,查阅资料后,正确写法如下: text.setTextColor(context.getResources().getColor(R.color.black)); 或: text.setTextColor(getResources().getColorStateList(R.color.black)); Android代码中更改TextView颜色

android 在布局中动态添加控件

第一步 Java代码 final LayoutInflater inflater = LayoutInflater.from(this); 第二步:获取需要被添加控件的布局 Java代码 final LinearLayout lin = (LinearLayout) findViewById(R.id.LinearLayout01); 第三步:获取需要添加的布局(控件) Java代码 LinearLayout layout = (LinearLayout) inflater.inflate( R

Android项目中JNI技术生成并调用.so动态库实现详解

生成 jni方式有两种:一种是通过SWIG从C++代码生成过度的java代码:另一种是通过javah的方式从java代码自动生成过度的C++代码.两种方式下的步骤流程正好相反. 第一种方式:由于需要配置SWIG环境,有点麻烦了,所以往往大家不采用这个途径,参照博文http://my.oschina.net/liusicong/blog/314162. 第二种方式:javah的方式则通过shell指令就可以完成整个流程,该过程大概包括以下步骤: 编写 Java 代码.我们将从编写 Java 类开始

Android开发中无处不在的设计模式——动态代理模式

继续更新设计模式系列,写这个模式的主要原因是最近看到了动态代理的代码. 先来回顾一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式--Builder模式 - Android开发中无处不在的设计模式--观察者模式 - Android开发中无处不在的设计模式--原型模式 - Android开发中无处不在的设计模式--策略模式 动态代理模式在Java WEB中的应用简直是随处可见,尤其在Spring框架中大量的用到了动态代理:算是最重要

Android中样式及主题

Android应用程序中不可避免的需要使用的样式和主题,样式指定一般指定View的高度.字体.字体颜色.背景,Android里的样荐定义在Style.xml文件里.主题也是一种样式,只不过它是应用在整个Activity或application,而不只是View.两者基本相同,最大的区别就是作用的范围不一样.样式针对的是单个的View控件,主题的范围更广,还是直接开始动手写吧. 自定义的样式及主题 最简单新建一个Android项目都会有一个TextView内容是HelloWorld: <TextV