学习源
鸣谢:http://www.jianshu.com/p/5eac94143bd6
源码地址
https://github.com/jigongdajiang/FunDemo/tree/master
场景分析
1.黑夜白天模式
2.从服务器下载皮肤资源,加载任意皮肤
核心代码分析
1.根据皮肤文件自己创建资源加载类 Resources AssetManager。核心代码如下:
/**
* 根据皮肤资源路径创建对应的Resources
*/
public SkinResource(Context context, String skinPath) {
try{
Resources surperResource = context.getResources();
Configuration configuration = new Configuration();
DisplayMetrics displayMetrics = surperResource.getDisplayMetrics();
AssetManager assetManager = AssetManager.class.newInstance();
//添加本地下载好的皮肤
Method methodAddAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath",String.class);
methodAddAssetPath.setAccessible(true);
methodAddAssetPath.invoke(assetManager,skinPath);
mResources = new Resources(assetManager,displayMetrics,configuration);
//获取皮肤apk的包名
mPackageName = context
.getPackageManager()
.getPackageArchiveInfo(skinPath, PackageManager.GET_ACTIVITIES)
.packageName;
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 根据资源名称 如 @color/main_big_color中的main_big_color 解析资源属性进行重新设置
*/
@Override
public void skin(View view, String resName) {
if(view != null && view instanceof TextView){
SkinResource skinResource = getSkinResource();
ColorStateList color = skinResource.getColorByName(resName);
if(null != color){
((TextView)view).setTextColor(color);
}
}
}
2.连接View的创建,然后截取其属性信息,用第一步的新资源装在器重置View的皮肤属性信息。核心代码如下:
/**
* 通过源码得知,指定自己的LayoutInflaterFactory可以拦截View的创建
*/
private void installMyViewFactory() {
if (!SkinManager.getInstance().isInit()) {
SkinManager.getInstance().init(this);
}
LayoutInflater layoutInflater = LayoutInflater.from(this);
if (layoutInflater.getFactory() == null) {
//仿照AppCompatActivity 的方法,这里一旦自己设置了,将不会走AppCompatActivity中的工厂
LayoutInflaterCompat.setFactory(layoutInflater, this);
}
}
/**
* 仿照系统的View创建过程,以实现兼容性
*/
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
// 创建View
View view = createView(parent, name, context, attrs);
// Log.e(TAG,"View-->"+view);
// 解析属性 src background textColor
// 1. 一个Activity 对应对个SkinView
List<SkinAttr> skinAttrs = SkinAttrSupport.getSkinAttrs(context, attrs);
if (null != view) {
SkinView skinView = new SkinView(view, skinAttrs);
// 统一交给SkinManager去管理
manageSkinView(skinView);
String currentSkinPath = SkinSpUtil.getInstance().getCurrentSkinPath();
if (SkinConfig.SKIN_FILE_QUALIFIED == SkinManager.getInstance().autoLoadCheckSkinPath(currentSkinPath)) {
//自动切换皮肤
skinView.skin();
}
}
return view;
}
框架的使用
1.所有需要换肤的Activity继承自BaseSkinActivity
2.下载完皮肤直接调用SkinManager.getInstance().loadSkin(skinPath)即可
/**
* 点击换肤按钮
*/
public void skinChange(View view) {
String skinPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "black.skin";
int result = SkinManager.getInstance().loadSkin(skinPath);
if (SkinConfig.SKIN_CHANGE_SUCCESS == result) {
Toast.makeText(this, "换肤成功", Toast.LENGTH_LONG).show();
}
}