Android换肤之——Theme换肤

本文介绍如何在Android应用中通过更改Theme实现界面风格的切换,包括创建自定义属性、定义不同主题样式及在运行时动态切换主题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      Android中通过更改Theme来更换皮肤也是常用的一种方法  也是实现夜间模式的一种

具体步骤:

首先在attrs.xml文件中,给需要改变Theme的控件自定义属性值,这里就已根布局的背景,和Textview的颜色为例:

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

然后再style.xml文件中设置你所需要的主题 有几个主题就设置几个 以便以后切换:

  <style name="BlueStyle">
        <item name="root_view_bg">@color/blue</item>
        <item name="text_color">@color/white</item>
    </style>
    <style name="GreenStyle">
        <item name="root_view_bg">@color/green</item>
        <item name="text_color">@color/black</item>
    </style>

在布局文件中使用自定义的属性:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/root_view_bg"
    >

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="?attr/text_color"
        android:textSize="30sp"
        android:text="Hello World!" />
    <Button
        android:id="@+id/btn_change"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="change"/>
</RelativeLayout>

这里的 ?attr/root_view_bg  ?attr/text_color 就是我们自己设定的属性,当setTheme的时候可以跟着我们设定改变

这个时候我们只要在Activity中的setContentView ()之前调用setTheme(R.style.xxx)方法就可以使activity成为我们需要的主题颜色。

但是我们要是有一个按钮来点击切换主题的时候,在点击的方法中调用setTheme(R.style.xxx) 你会发现没有反应,因为要想让新生的Theme生效,需要重新启动activity重新刷新UI。这时候我们可以在setTheme(R.style.xxx) 方法的后面再调用一次setContentView()方法来实现更换主题。

                setTheme(R.style.GreenStyle);
                setContentView(R.layout.activity_main);
但是如果在我们的布局很复杂的情况下,在调用setContentView()就会有界面的闪烁 

我们可以通过重置属性来实现

        TypedValue typedValue = new TypedValue();
        newTheme.resolveAttribute(mArrId, typedValue, true); //<span style="font-family: Arial, Helvetica, sans-serif;">mArrId是自定义的属性的id</span>

为了方便扩展 封装几个类:

package com.chs.changeskin.view;

import android.content.res.Resources;
import android.util.TypedValue;
import android.view.View;

/**
 * 作者:chs on 2016/1/20 17:03
 * 邮箱:657083984@qq.com
 */
public abstract class ViewEntity {
    protected int mViewId;
    protected View mView;
    protected int mArrId;

    public ViewEntity(int mViewId, int mArrId) {
        this.mViewId = mViewId;
        this.mArrId = mArrId;
    }

    public ViewEntity(View mView, int mArrId) {
        this.mView = mView;
        this.mArrId = mArrId;
    }

    public abstract void setValue(Resources.Theme newTheme, int themeId);
    public int getViewId() {
        return mViewId;
    }

    public void setViewId(int viewId) {
        mViewId = viewId;
    }

    public View getView() {
        return mView;
    }

    public void setView(View view) {
        this.mView = view;
    }

    public int getArrId() {
        return mArrId;
    }

    public void setArrId(int arrId) {
        this.mArrId = arrId;
    }
    protected int getColor(Resources.Theme newTheme) {
        TypedValue typedValue = new TypedValue();
        newTheme.resolveAttribute(mArrId, typedValue, true);
        return typedValue.data;
    }
}
package com.chs.changeskin.view;

import android.content.res.Resources;
import android.view.View;

/**
 * 作者:chs on 2016/1/20 17:08
 * 邮箱:657083984@qq.com
 */
public class BgViewEntity extends ViewEntity {

    public BgViewEntity(int mViewId, int mArrId) {
        super(mViewId, mArrId);
    }

    public BgViewEntity(View mView, int mArrId) {
        super(mView, mArrId);
    }

    @Override
    public void setValue(Resources.Theme newTheme, int themeId) {
        if ( mView != null ) {
            mView.setBackgroundColor(getColor(newTheme));
        }
    }
}

package com.chs.changeskin.view;

import android.content.res.Resources;
import android.view.View;
import android.widget.TextView;

/**
 * 作者:chs on 2016/1/20 17:08
 * 邮箱:657083984@qq.com
 */
public class TextViewEntity extends ViewEntity {
    public TextViewEntity(int mViewId, int mArrId) {
        super(mViewId, mArrId);
    }

    public TextViewEntity(View mView, int mArrId) {
        super(mView, mArrId);
    }

    @Override
    public void setValue(Resources.Theme newTheme, int themeId) {
        if (mView == null) {
            return;
        }
        ((TextView) mView).setTextColor(getColor(newTheme));
    }
}
activity中初始化所有需要改变的控件 

public static List<ViewEntity> ViewEntitys = new ArrayList<>();

 private void initViewEntitys() {
        ViewEntitys.add(new BgViewEntity(findViewById(R.id.root), R.attr.root_view_bg));
        ViewEntitys.add(new TextViewEntity(findViewById(R.id.tv_text), R.attr.text_color));
    }

    void changeTheme(){
        if(curTme){
            setTheme(R.style.GreenStyle);
            resetAttr(R.style.GreenStyle);
        }else {
            setTheme(R.style.BlueStyle);
            resetAttr(R.style.BlueStyle);
        }
        curTme = !curTme;//切换使用
    }
    private void resetAttr(int themeId) {
        Resources.Theme curTheme = getTheme();
        for(ViewEntity entity:ViewEntitys){
            entity.setValue(curTheme,themeId);
        }
    }

mainActivity代码:

package com.chs.changeskin;

import android.content.Intent;
import android.content.res.Resources;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.chs.changeskin.view.BgViewEntity;
import com.chs.changeskin.view.TextViewEntity;
import com.chs.changeskin.view.ViewEntity;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    public static List<ViewEntity> ViewEntitys = new ArrayList<>();
    RelativeLayout root;
    TextView tv_text;
    Button button;
    boolean curTme = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTheme(R.style.BlueStyle);
        setContentView(R.layout.activity_main);
        initView();
        initEvent();
        initViewEntitys();
    }

    private void initViewEntitys() {
        ViewEntitys.add(new BgViewEntity(findViewById(R.id.root), R.attr.root_view_bg));
        ViewEntitys.add(new TextViewEntity(findViewById(R.id.tv_text), R.attr.text_color));
    }

    private void initView() {
        root = (RelativeLayout) findViewById(R.id.root);
        tv_text = (TextView) findViewById(R.id.tv_text);
        button = (Button) findViewById(R.id.btn_change);
    }

    private void initEvent() {
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                changeTheme();
//                setTheme(R.style.GreenStyle);
//                setContentView(R.layout.activity_main);
            }
        });
    }

    void changeTheme(){
        if(curTme){
            setTheme(R.style.GreenStyle);
            resetAttr(R.style.GreenStyle);
        }else {
            setTheme(R.style.BlueStyle);
            resetAttr(R.style.BlueStyle);
        }
        curTme = !curTme;
    }
    private void resetAttr(int themeId) {
        Resources.Theme curTheme = getTheme();
        for(ViewEntity entity:ViewEntitys){
            entity.setValue(curTheme,themeId);
        }
    }

}

效果图:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值