Android(12)Preference(三)抽象管理
问题发生背景:
假如我们现在有一个设置页面,虽然我们可以通过获取Preference 实例去set 一些Click 、Change 监听,但是当我们的业务逻辑增加并且复杂的时候,会发现我们每次都要先去找到一个实例才能去设置,这个时候就需要分离UI逻辑和数据逻辑了,比如我希望点击的时候只是通过传过来的key 判断UI的变化,是跳转到下一个设置页面还是弹出一个对话框等;点击Switch 改变值的时候通过key 判断,意思就是把原来的点击处理一票子逻辑拆分成俩部分方便管理。
开始抽象,准备动手!
-
先抽象出一个PreferenceFragmentCompat 容器的Activity 。
abstract class BaseSettingsActivity: AppCompatActivity() {
abstract val hostFragmentName: String
protected val activityLayoutRes = R.layout.activity_main
var hostFragment: BaseSettingsFragment? = null
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 = 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 :
abstract class BaseSettingsFragment: PreferenceFragmentCompat() {
abstract val xmlRes: Int
val preferenceKeys = mutableListOf<String>()
abstract fun handleInteractionLogic(preference: Preference, prefKey: String): Boolean
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 :
<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">
<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
override fun handleInteractionLogic(preference: Preference, prefKey: String): Boolean {
TODO("Not yet implemented")
}
override fun handleDataLogic(preference: Preference, prefKey: String) {
TODO("Not yet implemented")
}
}
}
|