zoukankan      html  css  js  c++  java
  • 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>

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

    在需要切换显示不同themeactivity中,一些博客中在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/

  • 相关阅读:
    QListView和QListWidget的区别
    Qt下QTableWidget的使用
    用c++封装linux系统调用
    读写锁的简单示例
    SQL 使用序列
    SQL 事务
    SQL ALTER TABLE 命令
    SQL 语句快速参考
    java中三种常见内存溢出错误的处理方法(good)
    Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
  • 原文地址:https://www.cnblogs.com/carbs/p/5015644.html
Copyright © 2011-2022 走看看