android主题切换框架,Android主题切换日夜间模式与换肤框架小结
首先,Activity会在onCreate中初始化Factory,我们没有设置就返回系统默认的:
@Override
public void installViewFactory() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
if (layoutInflater.getFactory() == null) {
LayoutInflaterCompat.setFactory(layoutInflater, this); //系统默认的
} else {
if (!(LayoutInflaterCompat.getFactory(layoutInflater)
instanceof AppCompatDelegateImplV9)) {
Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
+ " so we can not install AppCompat's");
}
}
}
Factory会在layoutInflater.inflate,最终会走Factory.createView,看看系统的:
@Override
public View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
if (mAppCompatViewInflater == null) {
mAppCompatViewInflater = new AppCompatViewInflater();
}
boolean inheritContext = false;
if (IS_PRE_LOLLIPOP) {
inheritContext = (attrs instanceof XmlPullParser)
// If we have a XmlPullParser, we can detect where we are in the layout
? ((XmlPullParser) attrs).getDepth() > 1
// Otherwise we have to use the old heuristic
: shouldInheritContext((ViewParent) parent);
}
return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,
IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) */
true, /* Read read app:theme as a fallback at all times for legacy reasons */
VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */
);
}
再看下去:
public final View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs, boolean inheritContext,
boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
final Context originalContext = context;
// We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
// by using the parent's context
if (inheritContext && parent != null) {
context = parent.getContext();
}
if (readAndroidTheme || readAppTheme) {
// We then apply the theme on the context, if specified
context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
}
if (wrapContext) {
context = TintContextWrapper.wrap(context);
}
View view = null;
// We need to 'inject' our tint aware Views in place of the standard framework versions
switch (name) {
case "TextView":
view = new AppCompatTextView(context, attrs);
break;
case "ImageView":
view = new AppCompatImageView(context, attrs);
break;
case "Button":
view = new AppCompatButton(context, attrs);
break;
case "EditText":
view = new AppCompatEditText(context, attrs);
break;
case "Spinner":
view = new AppCompatSpinner(context, attrs);
break;
case "ImageButton":
view = new AppCompatImageButton(context, attrs);
break;
case "CheckBox":
view = new AppCompatCheckBox(context, attrs);
break;
case "RadioButton":
view = new AppCompatRadioButton(context, attrs);
break;
case "CheckedTextView":
view = new AppCompatCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = new AppCompatAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = new AppCompatMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = new AppCompatRatingBar(context, attrs);
break;
case "SeekBar":
view = new AppCompatSeekBar(context, attrs);
break;
}
if (view == null && originalContext != context) {
// If the original context does not equal our themed context, then we need to manually
// inflate it using the name so that android:theme takes effect.
view = createViewFromTag(context, name, attrs);
}
if (view != null) {
// If we have created a view, check it's android:onClick
checkOnClickListener(view, attrs);
}
return view;
}
可以看到系统也是根据XML解析的名字new出控件,但上面都是AppCompat类型,其他类型其实的通过类加载器创建出来的,那么XML使用TextView其实是AppCompatTextView,利用这一个原理,看看Android-skin-support:
private View createViewFromFV(Context context, String name, AttributeSet attrs) {
View view = null;
if (name.contains(".")) {
return null;
}
switch (name) {
case "View":
view = new SkinCompatView(context, attrs);
break;
case "LinearLayout":
view = new SkinCompatLinearLayout(context, attrs);
break;
case "RelativeLayout":
view = new SkinCompatRelativeLayout(context, attrs);
break;
case "FrameLayout":
view = new SkinCompatFrameLayout(context, attrs);
break;
case "TextView":
view = new SkinCompatTextView(context, attrs);
break;
case "ImageView":
view = new SkinCompatImageView(context, attrs);
break;
case "Button":
view = new SkinCompatButton(context, attrs);
break;
case "EditText":
view = new SkinCompatEditText(context, attrs);
break;
case "Spinner":
view = new SkinCompatSpinner(context, attrs);
break;
case "ImageButton":
view = new SkinCompatImageButton(context, attrs);
break;
case "CheckBox":
view = new SkinCompatCheckBox(context, attrs);
break;
case "RadioButton":
view = new SkinCompatRadioButton(context, attrs);
break;
case "RadioGroup":
view = new SkinCompatRadioGroup(context, attrs);
break;
case "CheckedTextView":
view = new SkinCompatCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = new SkinCompatAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = new SkinCompatMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = new SkinCompatRatingBar(context, attrs);
break;
case "SeekBar":
view = new SkinCompatSeekBar(context, attrs);
break;
case "ProgressBar":
view = new SkinCompatProgressBar(context, attrs);
break;
case "ScrollView":
view = new SkinCompatScrollView(context, attrs);
break;
}
return view;
}
这就返回了自己定制好的View了,那么回到前面,我们需要在super.onCreate前设置自己的Factory,不可能每个Activity都设置一遍,那么利用Application.ActivityLifecycleCallbacks统一设置:
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity instanceof AppCompatActivity) {
LayoutInflater layoutInflater = activity.getLayoutInflater();
try {
Field field = LayoutInflater.class.getDeclaredField("mFactorySet");
field.setAccessible(true);
field.setBoolean(layoutInflater, false);
LayoutInflaterCompat.setFactory(activity.getLayoutInflater(),
getSkinDelegate((AppCompatActivity) activity));
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
updateStatusBarColor(activity);
updateWindowBackground(activity);
}
}
android主题切换框架,Android主题切换日夜间模式与换肤框架小结相关推荐
- Android-skin-support 一款用心去做的Android 换肤框架
介绍 Github地址: https://github.com/ximsfei/Android-skin-support Android-skin-support: 一款用心去做的Android 换肤 ...
- android的资源混淆和压缩工具,换肤框架
介绍一款可以对android资源进行压缩的工具,超好用(已经在项目中使用到) https://github.com/shwenzhang/AndResGuard Android-skin-suppor ...
- Android换肤功能实现与换肤框架QSkinLoader使用方式介绍
框架地址:https://github.com/qqliu10u/QSkinLoader 效果图 https://github.com/qqliu10u/QSkinLoader/raw/master/ ...
- android自动夜间模式,Android实现日夜间模式的深入理解
在本篇文章中给出了三种实现日间/夜间模式切换的方案,三种方案综合起来可能导致文章的篇幅过长,请耐心阅读. 1.使用 setTheme的方法让 Activity重新设置主题: 2.设置 Android ...
- Android 手写实现插件化换肤框架 兼容Android10 Android11
目录 一.收集所有需要换肤的view及相关属性 二.统一为所有Activity设置工厂(兼容Android9以上) 三.加载皮肤包资源 四.处理支持库或者自定义view的换肤 五.处理状态栏换肤 六. ...
- android 换肤框架搭建及使用 (3 完结篇)
本系列计划3篇: Android 换肤之资源(Resources)加载(一) setContentView() / LayoutInflater源码分析(二) 换肤框架搭建(三) - 本篇 tips: ...
- 换肤框架Android-Skin-Support问题记录
换肤框架Android-Skin-Support问题记录 换肤框架Android-Skin-Support问题记录 换肤框架Android-Skin-Support问题记录 换肤框架使用 问题 1:其 ...
- 红橙Darren视频笔记 换肤框架4 换肤的功能完善 内存泄漏分析
上一篇完成了换肤框架的基本搭建,这一次 我们继续补完上一次遗留的一些可以完善的部分 1.完善换肤 1.1退出后再进入应用 不会丢失上一次保存的皮肤 基本原理:将上一次切换的皮肤path保存在Share ...
- Leakcanary原理解析以及换肤框架skin的原理分析
一.错误现场 java.lang.ClassCastException: androidx.appcompat.widget.TintContextWrapper cannot be cast to ...
最新文章
- vscode最好看的主题推荐_新学期,幼儿园环创主题墙及楼道,这样布置最好看!...
- c:\program files\microsoft visual studio\vc98\mfc\include\afxv_w32.h(14) : fatal error C1189:
- 输入密码后默认回车提交登录事件
- JS代码对表格进行新增时无法解析HTML代码的解决方式
- 解决Excel装了excel link 加载宏之后,打开excel就自动打开matlab的方法
- 发掘 iGoogle
- 计算机上机考试自我检查800字,学生检讨书800字反省自己【三篇】
- [译]const T vs. T const ——Dan Saks 【翻译】
- 网上打印怎么那么便宜,网上打印平台哪家比较便宜
- 机器学习(八):CS229ML课程笔记(4)——生成学习,高斯判别分析,朴素贝叶斯
- linux spark单节点环境搭建,Linux下基于Hadoop的Spark1.2单机安装
- 量子退火Python实战(3):投资组合优化(Portfolio) MathorCup2023特供PyQUBO教程
- 拼多多面试——算法实习面试
- out了吧,这份最新阿里、腾讯、华为、字节跳动等大厂的薪资和职级对比,你都没看过?
- 换脸原理,使用GAN网络再造ZAO应用:深度学习和神经网络介绍
- 隐私泄露、AI换脸存风险 11家企业被约谈
- 高分2(GF2)卫星数据系列处理
- ios svn repository
- 计算机怎么强制显示桌面,电脑显示桌面太大怎么办
- 计算机办公软件培训策划,计算机办公软件应用培训教学计划.pdf
热门文章
- 海龟绘图两小时上手C语言 - 3 正方形螺旋线
- 做游戏,学编程(C语言) 10 僵尸危机
- 锤子系统宣布回归 或将推新品
- 在内存只有24KB的电脑上写操作系统,是怎样的体验?
- 为什么软件最终都会变得很复杂?
- Redis 在 MySql 中的优化历程
- 英特尔发布边缘软件中心,抢滩 650 亿美元智能边缘市场!
- OPPO 回应“不务正业”生产口罩;旧款 iPhone 降速被罚 2500 万欧元;Angular 9.0.0 发布| 极客头条...
- @程序员,如何在编程面试中脱颖而出?
- X 射线技术揭示芯片的秘密!