首先,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主题切换日夜间模式与换肤框架小结相关推荐

  1. Android-skin-support 一款用心去做的Android 换肤框架

    介绍 Github地址: https://github.com/ximsfei/Android-skin-support Android-skin-support: 一款用心去做的Android 换肤 ...

  2. android的资源混淆和压缩工具,换肤框架

    介绍一款可以对android资源进行压缩的工具,超好用(已经在项目中使用到) https://github.com/shwenzhang/AndResGuard Android-skin-suppor ...

  3. Android换肤功能实现与换肤框架QSkinLoader使用方式介绍

    框架地址:https://github.com/qqliu10u/QSkinLoader 效果图 https://github.com/qqliu10u/QSkinLoader/raw/master/ ...

  4. android自动夜间模式,Android实现日夜间模式的深入理解

    在本篇文章中给出了三种实现日间/夜间模式切换的方案,三种方案综合起来可能导致文章的篇幅过长,请耐心阅读. 1.使用 setTheme的方法让 Activity重新设置主题: 2.设置 Android ...

  5. Android 手写实现插件化换肤框架 兼容Android10 Android11

    目录 一.收集所有需要换肤的view及相关属性 二.统一为所有Activity设置工厂(兼容Android9以上) 三.加载皮肤包资源 四.处理支持库或者自定义view的换肤 五.处理状态栏换肤 六. ...

  6. android 换肤框架搭建及使用 (3 完结篇)

    本系列计划3篇: Android 换肤之资源(Resources)加载(一) setContentView() / LayoutInflater源码分析(二) 换肤框架搭建(三) - 本篇 tips: ...

  7. 换肤框架Android-Skin-Support问题记录

    换肤框架Android-Skin-Support问题记录 换肤框架Android-Skin-Support问题记录 换肤框架Android-Skin-Support问题记录 换肤框架使用 问题 1:其 ...

  8. 红橙Darren视频笔记 换肤框架4 换肤的功能完善 内存泄漏分析

    上一篇完成了换肤框架的基本搭建,这一次 我们继续补完上一次遗留的一些可以完善的部分 1.完善换肤 1.1退出后再进入应用 不会丢失上一次保存的皮肤 基本原理:将上一次切换的皮肤path保存在Share ...

  9. Leakcanary原理解析以及换肤框架skin的原理分析

    一.错误现场 java.lang.ClassCastException: androidx.appcompat.widget.TintContextWrapper cannot be cast to ...

最新文章

  1. vscode最好看的主题推荐_新学期,幼儿园环创主题墙及楼道,这样布置最好看!...
  2. c:\program files\microsoft visual studio\vc98\mfc\include\afxv_w32.h(14) : fatal error C1189:
  3. 输入密码后默认回车提交登录事件
  4. JS代码对表格进行新增时无法解析HTML代码的解决方式
  5. 解决Excel装了excel link 加载宏之后,打开excel就自动打开matlab的方法
  6. 发掘 iGoogle
  7. 计算机上机考试自我检查800字,学生检讨书800字反省自己【三篇】
  8. [译]const T vs. T const ——Dan Saks 【翻译】
  9. 网上打印怎么那么便宜,网上打印平台哪家比较便宜
  10. 机器学习(八):CS229ML课程笔记(4)——生成学习,高斯判别分析,朴素贝叶斯
  11. linux spark单节点环境搭建,Linux下基于Hadoop的Spark1.2单机安装
  12. 量子退火Python实战(3):投资组合优化(Portfolio) MathorCup2023特供PyQUBO教程
  13. 拼多多面试——算法实习面试
  14. out了吧,这份最新阿里、腾讯、华为、字节跳动等大厂的薪资和职级对比,你都没看过?
  15. 换脸原理,使用GAN网络再造ZAO应用:深度学习和神经网络介绍
  16. 隐私泄露、AI换脸存风险 11家企业被约谈
  17. 高分2(GF2)卫星数据系列处理
  18. ios svn repository
  19. 计算机怎么强制显示桌面,电脑显示桌面太大怎么办
  20. 计算机办公软件培训策划,计算机办公软件应用培训教学计划.pdf

热门文章

  1. 海龟绘图两小时上手C语言 - 3 正方形螺旋线
  2. 做游戏,学编程(C语言) 10 僵尸危机
  3. 锤子系统宣布回归 或将推新品
  4. 在内存只有24KB的电脑上写操作系统,是怎样的体验?
  5. 为什么软件最终都会变得很复杂?
  6. Redis 在 MySql 中的优化历程
  7. 英特尔发布边缘软件中心,抢滩 650 亿美元智能边缘市场!
  8. OPPO 回应“不务正业”生产口罩;旧款 iPhone 降速被罚 2500 万欧元;Angular 9.0.0 发布| 极客头条...
  9. @程序员,如何在编程面试中脱颖而出?
  10. X 射线技术揭示芯片的秘密!