代码编织梦想

Android(12)Preference(三)抽象管理

问题发生背景:

假如我们现在有一个设置页面,虽然我们可以通过获取Preference实例去set一些ClickChange监听,但是当我们的业务逻辑增加并且复杂的时候,会发现我们每次都要先去找到一个实例才能去设置,这个时候就需要分离UI逻辑和数据逻辑了,比如我希望点击的时候只是通过传过来的key判断UI的变化,是跳转到下一个设置页面还是弹出一个对话框等;点击Switch改变值的时候通过key判断,意思就是把原来的点击处理一票子逻辑拆分成俩部分方便管理。

在这里插入图片描述

开始抽象,准备动手!

  • 先抽象出一个PreferenceFragmentCompat容器的Activity

    • 有对应页面的标题
    • 统一风格的背景和Toobar
    abstract class BaseSettingsActivity: AppCompatActivity() {
    
        // 根Fragment名字
        abstract val hostFragmentName: String
    
        protected val activityLayoutRes = R.layout.activity_main
    
        var hostFragment: BaseSettingsFragment? = null
    
        // Toolbar相关
        protected var actionBar: ActionBar? = null
        protected lateinit var toolBar: Toolbar
        protected var collapsingToolbarLayout: CollapsingToolbarLayout? = null
        protected var appBarLayout: AppBarLayout? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(activityLayoutRes)
    
            // 设置协调布局和toolbar
            toolBar = findViewById(R.id.toolbar)
            setSupportActionBar(toolBar)
            actionBar = supportActionBar
            actionBar?.let {
                it.setDisplayHomeAsUpEnabled(true)
                it.setHomeButtonEnabled(true)
                it.setDisplayShowTitleEnabled(true)
            }
    
            toolBar.apply {
                setNavigationOnClickListener {
                    finishAndRemoveTask()
                }
            }
            collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar)
            appBarLayout = findViewById(R.id.appbar_layout)
            collapsingToolbarLayout?.let {
                it.title = title
            }
           
            val fragment = supportFragmentManager.fragmentFactory.instantiate(
                this.classLoader,
                hostFragmentName
            )
            hostFragment = fragment as BaseSettingsFragment
            supportFragmentManager
                .beginTransaction()
                .replace(
                    R.id.setting_fragment_container,
                    fragment
                ).commit()
        }
    }
    
  • 再抽象出一个PreferenceFragmentCompat:

    • 处理UI交互
    • 处理数据逻辑
    abstract class BaseSettingsFragment: PreferenceFragmentCompat() {
    
        // 设置布局资源id
        abstract val xmlRes: Int
    
        // 这个页面上可见的Preference的key
        val preferenceKeys = mutableListOf<String>()
    
        /**
         * 处理UI相关的逻辑
         *
         * @param preference Preference
         * @param prefKey String
         * @return Boolean  是否消费
         */
        abstract fun handleInteractionLogic(preference: Preference, prefKey: String): Boolean
    
        /**
         * 处理数据相关逻辑
         *
         * @param preference Preference
         * @param prefKey String
         */
        abstract fun handleDataLogic(preference: Preference, prefKey: String)
    
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(xmlRes, rootKey)
        }
    
        override fun onPreferenceTreeClick(preference: Preference): Boolean {
            return handleInteractionLogic(preference, preference.key)
        }
    }
    
  • 搞一个自己的Preference:

    • attr.xml中定义自己的属性
    <resources>
        <attr name="myPreferenceStyle" format="reference"/>
    
        <declare-styleable name="MyPreference">
            <attr name="myPfTitleTextColor" format="color"/>
            <attr name="myPfTitleTextSize" format="dimension"/>
        </declare-styleable>
    </resources>
    
    • theme.xml定义一个style指定myPreferenceStyle,记得<applicatiopn/>themme要指定为我们的哟
    <resources xmlns:tools="http://schemas.android.com/tools">
        <!-- Base application theme. -->
        <style name="Theme.MyApplication" parent="Theme.AppCompat.DayNight.NoActionBar">
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/purple_500</item>
            <item name="colorPrimaryVariant">@color/purple_700</item>
            <item name="colorOnPrimary">@color/white</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/teal_200</item>
            <item name="colorSecondaryVariant">@color/teal_700</item>
            <item name="colorOnSecondary">@color/black</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
            <!-- Customize your theme here. -->
    
            <item name="myPreferenceStyle">@style/MyPreferenceStyle</item>
        </style>
        
        
        // _-----------------------
    
        // 这里就可以统一设置自己定义的属性拉
        <style name="MyPreferenceStyle">
            <item name="myPfTitleTextColor">#FF4081</item>
            <item name="myPfTitleTextSize">20sp</item>
        </style>
        
        
    
        <style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
            <item name="android:textSize">22sp</item>
            <item name="android:textColor">#FF4081</item>
        </style>
    
        <style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
            <item name="android:textSize">36sp</item>
            <item name="android:textColor">#536DFE</item>
        </style>
    </resources>
    
  • 代码里使用属性:

    class MyPreference(
        context: Context,
        attributeSet: AttributeSet,
        defStyleAttr: Int = R.attr.myPreferenceStyle
    ): Preference(context, attributeSet, defStyleAttr) {
    
        val hostFragment by lazy {
            context.takeIf { it is BaseSettingsActivity }?.let {
                (it as BaseSettingsActivity).hostFragment
            }
        }
    
        private  var titleTextColor = 0
        private  var titleTextSize = 0f
    
        init {
            widgetLayoutResource = R.layout.my_widget
            context.obtainStyledAttributes(
                attributeSet,
                R.styleable.MyPreference, defStyleAttr, 0
            ).apply {
                titleTextColor =
                    getColor(R.styleable.MyPreference_myPfTitleTextColor, Color.BLACK)
                titleTextSize =
                    getDimension(R.styleable.MyPreference_myPfTitleTextSize, 10f)
                recycle()
            }
            hostFragment.takeIf { it is BaseSettingsFragment }?.preferenceKeys?.add(key)
        }
    
        override fun onBindViewHolder(holder: PreferenceViewHolder) {
            super.onBindViewHolder(holder)
            with(holder) {
                findViewById(android.R.id.title).takeIf { it is TextView }?.let {
                    (it as TextView).setTextColor(titleTextColor)
                    it.textSize = titleTextSize
                }
            }
            holder.findViewById(R.id.switchWidget).takeIf { it is Switch }?.let {
                (it as Switch).setOnCheckedChangeListener { buttonView, isChecked ->
                    hostFragment?.handleDataLogic(this, key)
                }
            }
        }
    }
    

使用

在搞完通用的之后了,就可以使用了:

class MyActivity: BaseSettingsActivity() {
    override val hostFragmentName: String
        get() = MyFragemnt::class.java.name
    
    class MyFragemnt: BaseSettingsFragment() {
        override val xmlRes: Int
            get() = R.xml.settings

        /**
         * 处理 UI
         * 
         * @param preference Preference
         * @param prefKey String
         * @return Boolean
         */
        override fun handleInteractionLogic(preference: Preference, prefKey: String): Boolean {
            TODO("Not yet implemented")
        }

        /**
         * 处理 数据
         * 
         * @param preference Preference
         * @param prefKey String
         */
        override fun handleDataLogic(preference: Preference, prefKey: String) {
            TODO("Not yet implemented")
        }
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/C_biubiubiu/article/details/122762930

android存储之preference和sqlite-爱代码爱编程

android preference: 在android中,最简单的持久化数据的办法是使用Preferences API,获取preference对象有三种方式,都是通过Activity对象的方法,获取的是android.content.SharedPreferences对象实例。 getPreferences():获取到作用域是本Acti

android preference 须知-爱代码爱编程

Android Preference 须知 一、理论   1.前言 在Android的应用开发中经常会涉及到设置界面的设计开发,为此Android提供了名为Preference的设置处理机制,沿用这种机制的话能省去开发者很多不必要的时间开支。 那Preference究竟是什么呢?看一下你Android手机里的“设置”这个应用

android进阶——preference详解之preference系的基本应用和管理(二)_飞_哥的博客-爱代码爱编程

引言 前面简单描述下了Preference的家族构成和基本知识,相信对于Preference早已不会陌生,肯定也跃跃欲试了吧,这篇文章就给大家总结下Preference、PreferenceActivity、PreferenceGroup、RingtonePreference的普通应用和管理,还有通过一些测试来验证一些机制和原理。 一、Preference

android进阶——preference详解之初识preference及preference系(一)_飞_哥的博客-爱代码爱编程

引言 很久没来得及更新博客了,时间总是不够,以前的知识还没来得及总结完毕,新的知识又源源不断地接触到,工作也很忙,但还是没有忘记自己最低点目标每个月至少四篇。好了,废话就到这里啦,开始进入正文,这篇文章如标题所言,(准确地来说应该需要好几篇文章可能才能总结完毕吧)主题只有一个另一种构建UI的方式——通过Preference去构建UI,而不是直接通过layo

android面试题(一)_myosotis5的博客-爱代码爱编程

自己总结了一些android的面试题,先写一部分,后续在补充   一、Android的四大组件是哪些?它们的作用是? 答:Activity是android程序和用户交互的界面,相当于单独的屏幕,需要为保持各界面的状态做很多持久化的事情,管理生命周期和一些逻辑跳转。      Service是一段长生命周期,没有用户界面的程序。可以一直在后台运行,也

android初级知识整理--面试_chaserye的博客-爱代码爱编程

ANR 一、什么是ANR Application Not Responding Activity-》5秒,Broadcast Receiver是10秒。在主线程中进行了耗时操作。 二、造成ANR的主要原因 主线程被IO操作

android & java面试详细个人总结-爱代码爱编程

Java部分: 一、八种数据类型以及他们的包装类 二、abstract与interface的区别(抽象类和接口)     1、关键字:抽象类 abstract         接口interface     2、抽象类继承 extends             接口实现 implements     3、子类继承抽象类和            

android 关于preference相关类的分析_android好难呀的博客-爱代码爱编程_prefernce 与 controller

系统里设置Settings app 里面是用Preference来做的,这些在其他app里也有涉及,比如dialer的设置部分,关于Preference这里涉及到一些类,以后会常用碰到的,做一个笔记记录和分析一下。 Act

preference组件探究之base,support及androidx对比_techmerger的博客-爱代码爱编程_leanbackpreferencefragment

Android提供的Preference组件使得APP设置页面的开发变得简单。 除了上述几篇文章讨论的Base包的Preference组件外,Android还提供了更为高效的Support包的Preference组件。 甚至于即将发布的Android Q预期将Support包的Preference组件全面替换为AndroidX包的组件。 本篇文章我们将探

Android Preference 笔记-爱代码爱编程

  目录   1.从PreferenceScreen 中 删除某个Preference 2. Preference类图 3.  Activity&Fragment / Preference&Fragment 组合使用 4. Actionbar (标题: 显示与隐藏 ) 4.1  AppCompatActivity  默认有标题