加载自定义属性实现app换肤功能

在各大app中的换肤换主题的功能实现。博主的理解就是一种当用户点击更换主题按钮,从服务器下载主题。这种就是插件化加载。另一种就是自定义多套的属性,当用户点击的时候,就通过反射机制,在达到更换主题皮肤的效果。

下面,就通过一个小例子来实现换肤的功能,初次尝试,如有纰漏的地方望大神指出,多多交流大笑大笑

怎么自定义属性,不明白的戳这里:http://blog.csdn.net/qq_17387361/article/details/53330969


1:在values文件夹下新建attr.xml文件(这里就拿颜色变化来说,当然也可以定义图片资源。)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="main_bg" format="reference|color"/>
    <attr name="main_textcolor" format="reference|color"/>
    <attr name="other_bg" format="reference|color"/>
    <attr name="other_textcolor" format="reference|color"/>

</resources>


2:在styles.xml中定义2套主题(里面的color值我用汉语拼音写的,通俗易懂)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--  主题A  -->
    <style name="theme_a" >
        <item name="main_bg">@color/bai</item>
        <item name="main_textcolor">@color/hei</item>
        <item name="other_bg">@color/bai</item>
        <item name="other_textcolor">@color/hei</item>
    </style>

    <!--  主题B -->
    <style name="theme_b" >
        <item name="main_bg">@color/hei</item>
        <item name="main_textcolor">@color/bai</item>
        <item name="other_bg">@color/hei</item>
        <item name="other_textcolor">@color/bai</item>
    </style>
</resources>

3:maniactivity的布局文件layout:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/main_bg"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">


    <Button
        android:id="@+id/btn_a"
        android:text="跳转"
        android:layout_centerInParent="true"
        android:textColor="?attr/main_textcolor"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_b"
        android:layout_centerHorizontal="true"
        android:text="换肤"
        android:layout_below="@id/btn_a"
        android:layout_marginTop="30dip"
        android:textColor="?attr/main_textcolor"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

注意其中自定义属性的引用:

android:textColor="?attr/main_textcolor"
效果图:



两个按钮,跳转是跳到另一个activity中。来模拟点击换肤的时候app其他的页面是否也做了变换。

另一个activity的布局很简单,这里直接给出效果图



这里注意仔细看,默认的颜色第一个activity背景是白色,按钮上面的字体颜色是黑色,第二个activity背景是白色,字体颜色是黑色


3:在来看activity类的代码

/**
 * Created by W61 on 2016/11/25.
 */

public class BaseActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SpUtils.init(this, "henry_theme");
        if(SpUtils.getInt("theme", 0) == 1) {
            setTheme(R.style.theme_b);
        } else {
            setTheme(R.style.theme_a);
        }
    }
}

public class MainActivity extends BaseActivity {

    private Button btn_a,btn_b;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        btn_a = (Button) findViewById(R.id.btn_a);
        btn_a.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this,OtherActivity.class));
            }
        });
        btn_b = (Button) findViewById(R.id.btn_b);
        btn_b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(SpUtils.getInt("theme", 0) == 1) {
                    SpUtils.setInt("theme", 0);
                    setTheme(R.style.theme_a);
                } else {
                    SpUtils.setInt("theme", 1);
                    setTheme(R.style.theme_b);
                }
                final View rootView = getWindow().getDecorView();
                ColorUiUtil.changeTheme(rootView, getTheme());
                startActivity(new Intent(MainActivity.this,MainActivity.class));
                finish();
            }
        });
    }

建了一个baseactivity便于统一管理,sputils是保存当前到底是那套皮肤的标识。大家可以自由发挥


注意:

startActivity(new Intent(MainActivity.this,MainActivity.class));
finish();
博主这个写这句代码是想点击换肤后当前页面也随之刷新。这里如果大家有更好的方法可以留言指出。


下面是一个帮助类(这个类拷贝网上大神写的方法)

/**
 * Created by chengli on 15/6/10.
 */
public class ColorUiUtil {
    /**
     * 切换应用主题
     *
     * @param rootView
     */
    public static void changeTheme(View rootView, Resources.Theme theme) {
        if (rootView instanceof ColorUiInterface) {
            ((ColorUiInterface) 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);
                }
            }
            if (rootView instanceof AbsListView) {
                try {
                    Field localField = AbsListView.class.getDeclaredField("mRecycler");
                    localField.setAccessible(true);
                    Method localMethod = Class.forName("android.widget.AbsListView$RecycleBin").getDeclaredMethod("clear", new Class[0]);
                    localMethod.setAccessible(true);
                    localMethod.invoke(localField.get(rootView), new Object[0]);
                } catch (NoSuchFieldException e1) {
                    e1.printStackTrace();
                } catch (ClassNotFoundException e2) {
                    e2.printStackTrace();
                } catch (NoSuchMethodException e3) {
                    e3.printStackTrace();
                } catch (IllegalAccessException e4) {
                    e4.printStackTrace();
                } catch (InvocationTargetException e5) {
                    e5.printStackTrace();
                }
            }
        } else {
            if (rootView instanceof ViewGroup) {
                int count = ((ViewGroup) rootView).getChildCount();
                for (int i = 0; i < count; i++) {
                    changeTheme(((ViewGroup) rootView).getChildAt(i), theme);
                }
            }
            if (rootView instanceof AbsListView) {
                try {
                    Field localField = AbsListView.class.getDeclaredField("mRecycler");
                    localField.setAccessible(true);
                    Method localMethod = Class.forName("android.widget.AbsListView$RecycleBin").getDeclaredMethod("clear", new Class[0]);
                    localMethod.setAccessible(true);
                    localMethod.invoke(localField.get(rootView), new Object[0]);
                } catch (NoSuchFieldException e1) {
                    e1.printStackTrace();
                } catch (ClassNotFoundException e2) {
                    e2.printStackTrace();
                } catch (NoSuchMethodException e3) {
                    e3.printStackTrace();
                } catch (IllegalAccessException e4) {
                    e4.printStackTrace();
                } catch (InvocationTargetException e5) {
                    e5.printStackTrace();
                }
            }
        }
    }

下面来看最终运行图:



大家可以仔细观察点击换肤前和换肤后的背景颜色和字体颜色。


这里建议大家在点击换肤时弹出一个加载框。来缓冲一下当前界面的刷新。


这是封装的一些列常用控件的jar包:http://download.csdn.net/detail/qq_17387361/9692620

这是本编博文的项目地址:http://download.csdn.net/detail/qq_17387361/9693602


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值