ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android 主题切换(theme),语种切换,动态获取自定义属性(attr)值

2020-06-05 19:07:19  阅读:331  来源: 互联网

标签:自定义 observer maxapp override theme 切换 fun import attr


1.开发环境:Android studio 3.4.0,kotlin实现
2.开发准备
①在values中添加资源文件【“new“ → "Values resouce file”】定义为”custom_theme_attrs“,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 控制app背景色 format:颜色值、资源引用 -->
    <attr name="custom_attr_app_bg" format="color|reference" />
    <!-- 控制app标题栏背景色 format:颜色值、资源引用 -->
    <attr name="custom_attr_app_title_layout_bg" format="color|reference" />
    <!-- 用户头像显示占位Drawable format:颜色值、资源引用 -->
    <attr name="custom_attr_user_photo_place_holder" format="color|reference" />
    <!-- 用户昵称字体颜色 format:颜色值、资源引用 -->
    <attr name="custom_attr_nickname_text_color" format="color|reference" />
    <!-- 用户备注字体颜色 format:颜色值、资源引用 -->
    <attr name="custom_attr_remark_text_color" format="color|reference" />
    <!-- 用户头像显示的透明度 format:尺寸值、资源引用 -->
    <attr name="custom_attr_user_photo_alpha" format="dimension|reference" />

    <attr name="titlebar_bg" format="color|reference"/>
    <attr name="titlebar_text_color" format="color|reference"/>
    <attr name="body_bg" format="color|reference"/>
    <attr name="body_text_color" format="color|reference"/>
    <attr name="title" format="string"/>
</resources>

②在资源文件”styles“中添加如下代码【添加主题】

<!-- 主题:白天 -->
    <style name="theme_day" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="titlebar_bg">#1EABF0</item>
        <item name="titlebar_text_color">#FFFFFF</item>
        <item name="body_bg">#F3F3F3</item>
        <item name="body_text_color">#333333</item>
    </style>
    
    <!-- 主题:夜晚 -->
    <style name="theme_night" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="titlebar_bg">#000000</item>
        <item name="titlebar_text_color">#FFFFFF</item>
        <item name="body_bg">#888888</item>
        <item name="body_text_color">#EAEAEA</item>
    </style>

    <!-- theme_day.chi_sim 表示继承theme_day -->
    <style name="theme_day.chi_sim">
        <item name="title">主题配置</item>
    </style>
    <style name="theme_night.eng">
        <item name="title">TopicConfig</item>
    </style>

3.添加观察者接口:

package com.zjhj.maxapp.theme

interface ThemeChangeObserver {
    /**
     * 加载当前主题
     */
    fun loadingCurrentTheme()

    /**
     * 主题改变后通知
     */
    fun notifyThemeChanged()
}

4.在BaseActivity中实现接口

package com.zjhj.maxapp.base

import android.content.Context
import android.os.Bundle
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import com.zjhj.maxapp.App
import com.zjhj.maxapp.R
import com.zjhj.maxapp.theme.ThemeChangeObserver
import com.zjhj.maxapp.utils.L //自定义日志类


/**
 * CreateTime 2020/4/2 09:10
 * Author LiuShiHua
 * Description:
 */
abstract class BaseActivity : AppCompatActivity(), ThemeChangeObserver {

    private val KEY_THEME_TAG = "myThemeTag"
    private var isChangeTheme: Boolean = false
    override fun onCreate(savedInstanceState: Bundle?) {
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
        setThemeBeforeCreate()
        super.onCreate(savedInstanceState)
        setContentView()
        initView()
        initData()
        getData()
    }

    /**
     */
    private fun setThemeBeforeCreate() {
        App.registerObserver(this)//将当前Acitivity注册成观察者
        loadingCurrentTheme()
    }

    /**
     * 加载当前主题
     * 需要在super.onCreate(savedInstanceState)之前执行才会生效
     */
    override fun loadingCurrentTheme() {
        when (getThemeTag()) {
            1 -> setTheme(R.style.theme_day_chi_sim)
            -1 -> setTheme(R.style.theme_night_eng)
        }
        L.d("loadingCurrentTheme:" + this::class.java)
    }

    abstract fun setContentView()
    abstract fun initView()
    abstract fun initData()
    abstract fun getData()

    /**
     * 获取当前主题类型
     */
    protected open fun getThemeTag(): Int {
        val preferences = getSharedPreferences("MaxTheme", Context.MODE_PRIVATE)
        return preferences.getInt(KEY_THEME_TAG, 1)
    }

    /**
     * 设置主题类型
     * 保存在sharedprferences中
     */
    protected open fun setThemeTag(tag: Int) {
        L.d("setThemeTag:" + tag)
        val preferences = getSharedPreferences("MaxTheme", Context.MODE_PRIVATE)
        val edit = preferences.edit()
        edit.putInt(KEY_THEME_TAG, tag)
        edit.commit()
        App.notifyByThemeChanged()
    }

    /**
     * 注销这个观察者
     */
    override fun onDestroy() {
        App.unregisterObserver(this)
        super.onDestroy()
    }
}

5.在APP(继承 Application)中管理观察者

package com.zjhj.maxapp

import android.app.Application
import android.content.Context
import com.zjhj.maxapp.theme.ThemeChangeObserver


/**
 * CreateTime 2020/4/9 09:40
 * Author LiuShiHua
 * Description:
 */
class App : Application() {


    companion object {//静态属性或方法
        lateinit var context: Context
        get

        private var mThemeChangeObserverStack: MutableList<ThemeChangeObserver>? = null

        /**
         * 获得observer堆栈
         */
        private fun obtainThemeChangeObserverStack(): MutableList<ThemeChangeObserver>? {
            if (mThemeChangeObserverStack == null) mThemeChangeObserverStack = ArrayList()
            return mThemeChangeObserverStack
        }

        /**
         * 向堆栈中添加observer
         */
        fun registerObserver(observer: ThemeChangeObserver?) {
            if (observer == null || obtainThemeChangeObserverStack()!!.contains(observer)) return
            obtainThemeChangeObserverStack()!!.add(observer)
        }

        /**
         * 从堆栈中移除observer
         */
        fun unregisterObserver(observer: ThemeChangeObserver?) {
            if (observer == null || !obtainThemeChangeObserverStack()!!.contains(observer)) return
            obtainThemeChangeObserverStack()!!.remove(observer)
        }

        /**
         * 向堆栈中所有对象发送更新UI的指令
         */
        fun notifyByThemeChanged() {
            val observers: List<ThemeChangeObserver>? = obtainThemeChangeObserverStack()
            for (observer in observers!!) {
                observer.loadingCurrentTheme() //
                observer.notifyThemeChanged() //
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        context = this
    }
}

5.在BaseActivity实例中去调用更换主题

package com.zjhj.maxapp

import com.zjhj.maxapp.base.BaseActivity
import kotlinx.android.synthetic.main.activity_theme.*

class ThemeActivity : BaseActivity() {
    override fun setContentView() {
        setContentView(R.layout.activity_theme)
    }

    override fun initView() {
        changeTheme.setOnClickListener {
            if (getThemeTag()==1) {//设置主题
                setThemeTag(-1)
            } else {
                setThemeTag(1)
            }
            recreate()//重新构建页面
        }
    }

    override fun initData() {

    }

    override fun getData() {

    }

    override fun notifyThemeChanged() {

    }
}

6.说明:网上有些建议是使用recreate()来重新构建页面就行,实际中很多Activity都无法使用recreate()来重新构建页面,或者想保存之前的页面信息而不希望页面重新构建,我这里使用的是在Activity中notifyThemeChanged中重新设置对应主题的属性值【感觉比较low】

...
 override fun notifyThemeChanged() {
        val typedValue = TypedValue()
        //获取当前主题下的titlebar_bg属性值,并赋给typedValue
        theme.resolveAttribute(R.attr.titlebar_bg, typedValue, true)
        //设置属性值【注意:属性是那种类型,设置的时候就用成那种类型】
        toolBar.setBackgroundColor(typedValue.data)
    }
...

实现效果:在主题设置也改变主题后其他页面跟这变化

标签:自定义,observer,maxapp,override,theme,切换,fun,import,attr
来源: https://blog.csdn.net/yingtian648/article/details/106528885

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有