美文网首页
Android 实现切换主题皮肤功能

Android 实现切换主题皮肤功能

作者: 极客匠 | 来源:发表于2019-03-06 14:17 被阅读0次

简介

通过观察许多主流的app可以发现都具有换肤功能,可以根据用户的喜欢定制自己的界面,比如微博、淘宝、网易新闻等,它们的皮肤(主题)大多数都是要通过下载然后再替换。替换的是什么呢?当然就是资源文件啦,再简单一点说,就是去替换界面上的字体、颜色、背景、图片这些东西。

正文

首先我们先来做个简单的一键切换主题的功能。查看代码如下:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>


    <style name="lightTheme">
        <item name="android:textColor">#eeeccc</item>
        <item name="android:background">#ffffff</item>
    </style>

    <style name="blackTheme">
        <item name="android:textColor">#ffffff</item>
        <item name="android:background">#000000</item>
    </style>
</resources>




package com.tuyasmart.tv.changetheme;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private boolean isClick;
    SharedPreferencesUtil sharedPreferencesUtil;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        sharedPreferencesUtil = new SharedPreferencesUtil(this, "sp");
        int theme = sharedPreferencesUtil.getIntValue("theme", 1);
        if (theme == 1){
            setTheme(R.style.lightTheme);
        }else{
            setTheme(R.style.blackTheme);
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.tv_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isClick) {
                    isClick = false;
                    sharedPreferencesUtil.putIntValue("theme",1);
                } else {
                    isClick = true;
                    sharedPreferencesUtil.putIntValue("theme",2);
                }
            }
        });
    }
}

但是这种情况下呢,一键切换皮肤,app需要退出,再打开才显示效果。同时,如果我们要是有多种主题的话,用这种方法,app就会变得很大。那我们就得想,皮肤能不能通过网络下载到本地,然后一键替换就可以了?答案是可以的。

这个方案的思路:把主题包做成一个apk,注意这个apk是不能在桌面上显示的,只能在设置中的app列表里查询到。然后在你的activity里取这个apk的资源。

先看资源包的app代码:

style.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:textColor">#ffffff</item>
        <item name="android:background">#000000</item>
    </style>

</resources>

AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tuyasmart.tv.childtheme">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <action android:name="android.intent.action.MAIN" />
        </activity>
    </application>

</manifest>

这里需要注意的是,我们把<category android:name="android.intent.category.LAUNCHER" />去掉了,就是为了确保app安装之后,不会在桌面上显示。

至此,只要把childTheme的apk安装到手机上,就可以动态加载主题了。但是这种方式也是不完美的,因为setTheme方法是要重启app之后才生效。体验上就不是很友好了,因为用户重启app的成本是比较高的。那我们有什么办法能解决这个问题呢?

首先我们知道的是app里面只有一个activity会做主题切换的功能,其他activity是不需要实现这个功能的。也就是说只要这个activity做了主题切换功能,其他activity只要是新启动的话,都会走oncreate,这样主题也就切换过去了。这样一想,只要我们能实现一个activity不重启activity就能实现切换皮肤的功能就OK了。代码如下:

首先我们先定义自定义属性:

<resources>

    <attr name="my_background" format="reference|color"/>
    <attr name="my_textcolor" format="reference|color"/>
</resources>

再定义主题

    <style name="lightTheme">
        <item name="my_textcolor">#eeeccc</item>
        <item name="my_background">#ffffff</item>
    </style>

    <style name="blackTheme">
        <item name="my_textcolor">#ffffff</item>
        <item name="my_background">#000000</item>
    </style>

再写布局文件

<?xml version="1.0" encoding="utf-8"?>
<com.tuyasmart.tv.changetheme.ThemeUIReleativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/my_background"
    tools:context=".MainActivity">

    <com.tuyasmart.tv.changetheme.ThemeTextView
        android:id="@+id/tv_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="?attr/my_background"
        android:text="change theme on click!"
        android:textColor="?attr/my_textcolor" />


</com.tuyasmart.tv.changetheme.ThemeUIReleativeLayout>

Mainactivity

package com.tuyasmart.tv.changetheme;

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends AppCompatActivity {

    private boolean isClick;
    SharedPreferencesUtil sharedPreferencesUtil;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.lightTheme);
        sharedPreferencesUtil = new SharedPreferencesUtil(this, "sp");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ThemeUIReleativeLayout mainView = findViewById(R.id.main_view);
        findViewById(R.id.tv_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isClick) {
                    isClick = false;
                    sharedPreferencesUtil.putIntValue("theme", 1);
                } else {
                    isClick = true;
                    sharedPreferencesUtil.putIntValue("theme", 2);
                }
                int theme = sharedPreferencesUtil.getIntValue("theme", 1);
                if (theme == 1) {
                    setTheme(R.style.lightTheme);
                } else {
                    //获取子app的style中的Apptheme,动态修改我们的主题。
                    int resourceId = getResourceId(getPackageContext(MainActivity.this
                            , "com.tuyasmart.tv.childtheme"), "style", "AppTheme");
//                    setTheme(resourceId);
                    setTheme(R.style.blackTheme);
                }
                changeTheme(mainView, getTheme());
            }
        });
    }

    /**
     * 获取其他apk的context
     *
     * @param context
     * @param packageName
     * @return
     */
    public static Context getPackageContext(Context context, String packageName) {
        try {
            return context.createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取指定type里面的name属性
     *
     * @param context
     * @param type
     * @param name
     * @return
     */
    public static int getResourceId(Context context, String type, String name) {
        return context.getResources().getIdentifier(name, type, context.getPackageName());
    }


    public static void changeTheme(View rootView, Resources.Theme theme) {
        //递归调用changeTheme-----递归调用setTheme了。
        if (rootView instanceof IThemeUI) {
            ((IThemeUI) rootView).setTheme(theme);
            if (rootView instanceof ViewGroup) {
                int count = ((ViewGroup) rootView).getChildCount();
                for (int i = 0; i < count; i++) {
                    changeTheme(((ViewGroup) rootView).getChildAt(i), theme);
                }
            }
        }
    }

}

至此,皮肤就可以动态修改了。通过动态下载的皮肤也是同样的道理使用。可以看如下代码:

childTheme:

添加attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="my_background" format="reference|color"/>
    <attr name="my_textcolor" format="reference|color"/>
</resources>

Style.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>


    <style name="blackTheme">
        <item name="my_textcolor">#ffffff</item>
        <item name="my_background">#000000</item>
    </style>

</resources>




findViewById(R.id.tv_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isClick) {
                    isClick = false;
                    sharedPreferencesUtil.putIntValue("theme", 1);
                } else {
                    isClick = true;
                    sharedPreferencesUtil.putIntValue("theme", 2);
                }
                int theme = sharedPreferencesUtil.getIntValue("theme", 1);
                if (theme == 1) {
                    setTheme(R.style.lightTheme);
                } else {
                    //获取子app的style中的Apptheme,动态修改我们的主题。
                    int resourceId = getResourceId(getPackageContext(MainActivity.this
                            , "com.tuyasmart.tv.childtheme"), "style", "blackTheme");
                    setTheme(resourceId);
//                    setTheme(R.style.blackTheme);
                }
                changeTheme(mainView, getTheme());
            }
        });

总结

皮肤替换就暂时说到这里,如果你的皮肤切换比较简单的话,就可以直接写在app里打包出去。如果皮肤种类过多的话,那就可以通过网络下载的模式进行替换。

相关文章

  • Android 实现切换主题皮肤功能

    简介 正文 首先我们先来做个简单的一键切换主题的功能。查看代码如下: 但是这种情况下呢,一键切换皮肤,app需要退...

  • 换肤

    Android主题切换(Theme)实现日夜间功能

  • 换肤

    Android换肤功能 什么是换肤?app的皮肤,比如说黑夜模式,切换之后整体风格改变成以黑色为主题色 换了什么?...

  • Android主题切换(Theme)实现日夜间功能

    前言 随着一款APP应用功能的不断完善,用户群体的不断增多,APP的更新也就不仅仅局限于功能需求,如何做好良好的用...

  • iOS 动态更换App图标

    该功能应用的场景 1、白天/夜间模式切换,在切换App主色调同时切换App图标。 2、各类皮肤主题(淘宝就可换肤)...

  • android各种效果库

    可能是最优雅的切换布局的方法 动态切换布局控件android 实现画板功能 本例详细分析了一个画板功能的实现过程,...

  • android 切换头像功能实现

    接到一个新需求,用户可以自己跟换自己的头像 1.可以使用相机或是选择照片2.剪切头像3.保存头像到本地 实现步骤:...

  • Android 切换主题(基础)

    参考 1、Android 切换主题以及换肤的实现 截图 1、默认打开 2、点击【换主题色】 需知 主题色运用:ma...

  • Android 切换主题(基础)

    参考 1、Android 切换主题以及换肤的实现 截图 1、默认打开 2、点击【换主题色】 需知 主题色运用:ma...

  • Android 切换主题风格(Theme换肤效果)

    参考 1、Android 切换主题以及换肤的实现 截图 1、默认打开 2、点击【换主题色】 需知 主题色运用:ma...

网友评论

      本文标题:Android 实现切换主题皮肤功能

      本文链接:https://www.haomeiwen.com/subject/wabtpqtx.html