Android 应用使用theme处理全局焦点框
背景
- 我的应用有个需求,要求处理keycode事件,进行焦点移动处理,必须定制指定的焦点框。
- 而系统的焦点框是固定了,为了保证平台的一致性,没办法直接修改。
问题
- 经过沟通,大部分都是自行修改了自己的background的属性,定制了焦点框,因为所需要处理的焦点框数量有限,进行了特殊修改
- 我的应用涉及的内容比较多,如果一个个修改,不仅工作量很大,还需要新增很多布局,并且修改掉原来的架构。
尝试
查看源码焦点框如何处理
系统也只是在overlay下面配置了一个属性,属性如下:
<item name="android:selectableItemBackground">@*android:drawable/item_background</item>
给这个属性配置了一个选择器,只要修改这个选择器,就可以改变系统全局焦点框。
是否有方法可以新增theme替换?
经过资料查询,需要新增一套主题包,替换才能起作用,工作量和周期太长,无法短时间内完成,且需要配合的相关方太多,暂时放弃此方案
是否可以在自己应用内部修改主题?
修改application应用的主题
- 首先修改应用自己的默认主题
<style name="Theme.system" parent="Theme.AppCompat.DayNight"><item name="android:windowNoTitle">true</item><item name="android:windowFullscreen">false</item><!-- 兼容API 7--><item name="android:windowActionBar">false</item><item name="android:windowIsTranslucent">true</item><item name="android:selectableItemBackground">@drawable/item_all_app_selector</item>
</style>
- Selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_focused="true"><shape android:shape="rectangle"><solid android:color="@color/transparent" /><stroke android:width="8dp" android:color="@color/view_on_click_background" /></shape></item><item android:state_focused="false"><shape><solid android:color="@color/transparent" /></shape></item></selector>
- 由于应用的特殊性,是没有Activity存在的,由addview和系统AlterDialog组成,修改系统主题之后,是没办法直接使用的。
- 首先修改系统Alter Dialog手动给他加载主题
private var mAllAppDialog: AllAppDialog = AllAppDialog(Utils.getContext(),R.style.Theme_dialog)
- 显示出来之后,发现有问题,因为之前是使用的系统默认的主题,加载了自定义主题时候,整个效果发生了变化,背景颜色和原有的高斯模糊都失效了,但是修改的焦点框是可以生效的
- 随后进行分析,我们使用的是通用的应用主题,也就是parent=“Theme.AppCompat.DayNight” 的主题是没办法给系统级别的AlterDialog用的。他不仅会给AlterDialog增加一个承载的黑色背景还会修改显示效果。
- 查看源码,源码是有专门为AlterDialog使用的主题。
创建新的主题
- 查看源码得到方向后,创建新的主题,parent=“Theme.AppCompat.Dialog.Alert”。仅增加一个指定的焦点框,并且修改背景为透明
<style name="Theme.dialog" parent="Theme.AppCompat.Dialog.Alert"><item name="android:selectableItemBackground">@drawable/item_all_app_selector</item><item name="android:background">@color/transparent</item>
</style>
- 再次尝试加载,加载成功,可以正常显示
- 扩展到其他的AlterDialog,统一使用加载指定的主题
异常情况
- 当扩展到其他的AlterDialog之后,发现有一个部分AlterDialog是无法正常加载主题的
- 因为每个对话框的业务逻辑和显示效果不同,一时没有分析到指定的问题
- 对比两类对话框,也没发现具体的问题原来
- 查找资料,也没有相关的资料说明
- 切换方向思考,对Context进行处理,为他加载主题
fun getWrapperContext():ContextThemeWrapper{return ContextThemeWrapper(Utils.getContext(),R.style.Theme_dialog)
}
- 使用新的Context,进行调试,可以生效。将所有异常的AlterDialog全部使用新的Content处理。
private var mMessageDialog: MessageDialog = MessageDialog(getWrapperContext())
private var mAccountDialog: AccountDialog = AccountDialog( getWrapperContext())
addview处理
- WindowManager 的addView方法进行加载的。addview方法是没办法直接加载主题的。
- 使用加载主题的Context初始化需要加载的View,再进行加载。主题正常加载
val wContext=ContextThemeWrapper(mContext,R.style.Theme_dialog)
Bar = View.inflate(wContext, R.layout.bar_view, null)
- 效果如下:
总结
修改应用全局焦点框
只对activity生效,主题如下
<style name="Theme.system" parent="Theme.AppCompat.DayNight"><item name="android:windowNoTitle">true</item><item name="android:windowFullscreen">false</item><!-- 兼容API 7--><item name="android:windowActionBar">false</item><item name="android:windowIsTranslucent">true</item><item name="android:selectableItemBackground">@drawable/item_all_app_selector</item>
</style>
修改指定的View焦点框
所有控件都可以用
<style name="Theme.dialog" parent="Theme.AppCompat.Dialog.Alert"><item name="android:selectableItemBackground">@drawable/item_all_app_selector</item><item name="android:background">@color/transparent</item>
</style>
构建带主题的Context
fun getWrapperContext():ContextThemeWrapper{return ContextThemeWrapper(Utils.getContext(),R.style.Theme_dialog)
}