}
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 its android:onClick
checkOnClickListener(view, attrs);
}
return view;
}
private View createViewFromTag(Context context, String name, AttributeSet attrs) {
if (name.equals(“view”)) {
name = attrs.getAttributeValue(null, “class”);
}
try {
mConstructorArgs[0] = context;
mConstructorArgs[1] = attrs;
if (-1 == name.indexOf(‘.’)) {
for (int i = 0; i < sClassPrefixList.length; i++) {
final View view = createView(context, name, sClassPrefixList[i]);
if (view != null) {
return view;
}
}
return null;
} else {
return createView(context, name, null);
}
} catch (Exception e) {
// We do not want to catch these, lets return null and let the actual LayoutInflater
// try
return null;
} finally {
// Don’t retain references on context.
mConstructorArgs[0] = null;
mConstructorArgs[1] = null;
}
}
/**
-
android:onClick doesn’t handle views with a ContextWrapper context. This method
-
backports new framework functionality to traverse the Context wrappers to find a
-
suitable target.
*/
private void checkOnClickListener(View view, AttributeSet attrs) {
final Context context = view.getContext();
if (!(context instanceof ContextWrapper) ||
(Build.VERSION.SDK_INT >= 15 && !ViewCompat.hasOnClickListeners(view))) {
// Skip our compat functionality if: the Context isn’t a ContextWrapper, or
// the view doesn’t have an OnClickListener (we can only rely on this on API 15+ so
// always use our compat code on older devices)
return;
}
final TypedArray a = context.obtainStyledAttributes(attrs, sOnClickAttrs);
final String handlerName = a.getString(0);
if (handlerName != null) {
view.setOnClickListener(new SkinAppCompatViewInflater.DeclaredOnClickListener(view, handlerName));
}
a.recycle();
}
private View createView(Context context, String name, String prefix)
throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
try {
if (constructor == null) {
// Class not found in the cache, see if it’s real, and try to add it
Class<? extends View> clazz = context.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
constructor = clazz.getConstructor(sConstructorSignature);
sConstructorMap.put(name, constructor);
}
constructor.setAccessible(true);
return constructor.newInstance(mConstructorArgs);
} catch (Exception e) {
// We do not want to catch these, lets return null and let the actual LayoutInflater
// try
return null;
}
}
/**
- Allows us to emulate the {@code android:theme} attribute for devices before L.
*/
private static Context themifyContext(Context context, AttributeSet attrs,
boolean useAndroidTheme, boolean useAppTheme) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
int themeId = 0;
if (useAndroidTheme) {
// First try reading android:theme if enabled
themeId = a.getResourceId(R.styleable.View_android_theme, 0);
}
if (useAppTheme && themeId == 0) {
// …if that didn’t work, try reading app:theme (for legacy reasons) if enabled
themeId = a.getResourceId(R.styleable.View_theme, 0);
if (themeId != 0) {
Log.i(LOG_TAG, "app:theme is now deprecated. "
- “Please move to using android:theme instead.”);
}
}
a.recycle();
if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
|| ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
// If the context isn’t a ContextThemeWrapper, or it is but does not have
// the same theme as we need, wrap it in a new wrapper
context = new ContextThemeWrapper(context, themeId);
}
return context;
}
/**
-
An implementation of OnClickListener that attempts to lazily load a
-
named click handling method from a parent or ancestor context.
*/
private static class DeclaredOnClickListener implements View.OnClickListener {
private final View mHostView;
private final String mMethodName;
private Method mResolvedMethod;
private Context mResolvedContext;
public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
mHostView = hostView;
mMethodName = methodName;
}
@Override
public void onClick(@NonNull View v) {
if (mResolvedMethod == null) {
resolveMethod(mHostView.getContext(), mMethodName);
}
try {
mResolvedMethod.invoke(mResolvedContext, v);
} catch (IllegalAccessException e) {
throw new IllegalStateException(
“Could not execute non-public method for android:onClick”, e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(
“Could not execute method for android:onClick”, e);
}
}
@NonNull
private void resolveMethod(@Nullable Context context, @NonNull String name) {
while (context != null) {
try {
if (!context.isRestricted()) {
final Method method = context.getClass().getMethod(mMethodName, View.class);
if (method != null) {
mResolvedMethod = method;
mResolvedContext = context;
return;
}
}
} catch (NoSuchMethodException e) {
// Failed to find method, keep searching up the hierarchy.
}
if (context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
} else {
// Can’t search up the hierarchy, null out and fail.
context = null;
}
}
final int id = mHostView.getId();
final String idText = id == View.NO_ID ? “” : " with id '"
- mHostView.getContext().getResources().getResourceEntryName(id) + “'”;
throw new IllegalStateException("Could not find method " + mMethodName
-
"(View) in a parent or ancestor Context for android:onClick "
-
"attribute defined on view " + mHostView.getClass() + idText);
}
}
}
- 解析属性
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
//拦截到View的创建 获取View之后要去解析
//1.创建View
View view = createView(parent, name, context, attrs);
//2.解析属性 src textColor background 自定义属性
Log.d(“huangxiaoguo”, view + “----------”);
if (view != null) {
List skinAttrs = SkinAttrSupport.getSkinAttrs(context, attrs);
}
return view;
}
- 皮肤属性解析的支持类
/**
-
Created by Administrator on 2018/8/3 0003.
-
皮肤属性解析的支持类
*/
public class SkinAttrSupport {
/**
-
获取SkinAttr的属性
-
@param context
-
@param attrs
-
@return
*/
public static List getSkinAttrs(Context context, AttributeSet attrs) {
// background src textColor
ArrayList skinAttrs = new ArrayList<>();
int attributeCount = attrs.getAttributeCount();
for (int i = 0; i < attributeCount; i++) {
//获取名称和值
String attrName = attrs.getAttributeName(i);
String attrValue = attrs.getAttributeValue(i);
Log.d(“huangxiaoguo”, “attrName—>” + attrName);
Log.d(“huangxiaoguo”, “attriValue—>” + attrValue);
//获取需要的资源
SkinType skinType = getSkinType(attrName);
if (skinType != null) {
//资源名称
String resName = geteResName(context, attrValue);
if (TextUtils.isEmpty(resName)) {
continue;
}
SkinAttr skinAttr = new SkinAttr(resName, skinType);
skinAttrs.add(skinAttr);
}
}
return skinAttrs;
}
/**
-
获取资源名称
-
@param context
-
@param attrValue
-
@return
*/
private static String geteResName(Context context, String attrValue) {
if (attrValue.startsWith(“@”)) {
attrValue = attrValue.substring(1);
int resId = Integer.parseInt(attrValue);
return context.getResources().getResourceEntryName(resId);
}
return null;
}
/**
-
通过名称获取SkinType
-
@param attrName
-
@return
*/
private static SkinType getSkinType(String attrName) {
SkinType[] skinTypes = SkinType.values();
for (SkinType skinType : skinTypes) {
if (skinType.getResName().equals(attrName)) {
return skinType;
}
}
return null;
}
}
- SkinManager管理
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
//拦截到View的创建 获取View之后要去解析
//1.创建View
View view = createView(parent, name, context, attrs);
//2.解析属性 src textColor background 自定义属性
Log.d(“huangxiaoguo”, view + “----------”);
if (view != null) {
List skinAttrs = SkinAttrSupport.getSkinAttrs(context, attrs);
SkinView skinView = new SkinView(view, skinAttrs);
//3.统一交给SkinManager管理
managerSkinView(skinView);
}
return view;
}
/**
-
统一管理SkinView
-
@param skinView
*/
protected void managerSkinView(SkinView skinView) {
List skinViews = SkinManager.getInstance().getSkinViews(this);
if (skinViews == null) {
skinViews = new ArrayList<>();
SkinManager.getInstance().register(this, skinViews);
}
skinViews.add(skinView);
}
- 皮肤管理类
/**
-
Created by Administrator on 2018/8/3 0003.
-
皮肤管理类
*/
public class SkinManager {
private static SkinManager mInstance;
private Context mContext;
private Map<Activity, List> mSkinViews = new HashMap<>();
private SkinResource mSkinResource;
static {
mInstance = new SkinManager();
}
public static SkinManager getInstance() {
return mInstance;
}
public void init(Context context) {
this.mContext = context.getApplicationContext();
}
/**
-
加载皮肤
-
@param skinPath
-
@return
*/
public int loadSkin(String skinPath) {
//初始化资源管理
mSkinResource = new SkinResource(mContext, skinPath);
//改变皮肤
Set keys = mSkinViews.keySet();
for (Activity key : keys) {
List skinViews = mSkinViews.get(key);
for (SkinView skinView : skinViews) {
skinView.skin();
}
}
return 0;
}
/**
-
恢复默认
-
@return
*/
public int restoreDefault() {
return 0;
}
/**
-
获取SkinView
-
@param activity
-
@return
*/
public List getSkinViews(Activity activity) {
return mSkinViews.get(activity);
}
/**
-
注册
-
@param activity
-
@param skinViews
*/
public void register(Activity activity, List skinViews) {
mSkinViews.put(activity, skinViews);
}
/**
-
获取当前皮肤资源
-
@return
*/
public SkinResource getSkinResource() {
return mSkinResource;
}
}
- 皮肤资源管理
/**
-
Created by Administrator on 2018/8/3 0003.
-
皮肤资源管理
*/
public class SkinResource {
//资源获取
private Resources mSkinResource;
private String mPackageName;
public SkinResource(Context context, String skinPath) {
try {
//读取本地资源
Resources superRes = context.getResources();
//创建AssetManager
AssetManager asset = AssetManager.class.newInstance();
//添加本地下载好的资源皮肤 Native层
Method method = AssetManager.class.getDeclaredMethod(“addAssetPath”, String.class);
//允许方法私有
method.setAccessible(true);
//反射方法
method.invoke(asset, Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + “red.skin”);
mSkinResource = new Resources(asset, superRes.getDisplayMetrics(), superRes.getConfiguration());
//获取报名
mPackageName = context.getPackageManager().getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES)
.packageName;
Log.d(“huangxiaoguo”, “mPackageName===>” + mPackageName);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
-
通过名字获取Drawable
-
@param resName
-
@return
*/
public Drawable getDrawableByName(String resName) {
try {
int resId = mSkinResource.getIdentifier(resName, “drawable”, mPackageName);
Log.d(“huangxiaoguo”, “drawable===>” + resId);
Drawable drawable = mSkinResource.getDrawable(resId);
return drawable;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
-
通过名字获取颜色
-
@param resName
-
@return
*/
public ColorStateList getColorByName(String resName) {
try {
int resId = mSkinResource.getIdentifier(resName, “color”, mPackageName);
Log.d(“huangxiaoguo”, “color===>” + resId);
ColorStateList color = mSkinResource.getColorStateList(resId);
return color;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- 封装View和属性bean
public class SkinView {
private View mView;
private List mAttrs;
public SkinView(View view, List attrs) {
this.mView = view;
this.mAttrs = attrs;
}
public void skin() {
for (SkinAttr attr : mAttrs) {
attr.skin(mView);
}
}
}
- 封装包名和要替换的内容
public class SkinAttr {
private String mResName;
private SkinType mType;
public SkinAttr(String resName, SkinType skinType) {
this.mResName=resName;
this.mType=skinType;
}
public void skin(View view) {
mType.skin(view, mResName);
}
}
- 获取想要的资源
/**
-
Created by Administrator on 2018/8/3 0003.
-
获取想要的资源
*/
public enum SkinType {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/2e7e72ce55206d19311fee23806fd3cd.jpeg)
最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。
Android高级架构师之路很漫长,一起共勉吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
}
public void skin(View view) {
mType.skin(view, mResName);
}
}
- 获取想要的资源
/**
-
Created by Administrator on 2018/8/3 0003.
-
获取想要的资源
*/
public enum SkinType {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-hR8MFabd-1713265043996)]
[外链图片转存中…(img-8xvdzbOQ-1713265043998)]
[外链图片转存中…(img-wixeJj76-1713265043999)]
[外链图片转存中…(img-O22dJLLT-1713265044000)]
[外链图片转存中…(img-sftkDDCb-1713265044001)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/2e7e72ce55206d19311fee23806fd3cd.jpeg)
最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。
[外链图片转存中…(img-iFVnbHuK-1713265044003)]
Android高级架构师之路很漫长,一起共勉吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!