经过SkinResource实现的应用皮肤动态识别切换
之前在公司的项目中,需要用到的需求是这样的,当一个应用开启时先去检测是否有对应的资源包(也是个APK,但是没有界面也就是Activity存在,只是单纯的资源),如果有则加载资源包里面的资源,没有的话则加载本身的资源。这样的好处是什么呢?就是以后要修改资源布局的时候,只要改资源包里对应的东西,然后将新的资源包加载进系统就行了,而不用每次都要改本身的应用。大大方便了后续的开发和维护。今天趁着不用加班,有空的时间,整理了一下,不过一个多星期的东西了,凭记忆书写,不知道会不会漏了某些知识点,也在最后放上一个多星期前自己学习用的demo,到时用的时候可以先导入demo的应用apk,再导入皮肤包的apk,这样就能体会到差别了。
无图无真相,先来两张图作对比(第一张是用本应用的资源,第二张是导入了资源包调用资源包里的资源)
废话不多说,直接用代码说话:
1.放入这样的一个Java代码:
写一个SkinResource: 以实现资源的动态加载
package com.jrue.skintest; import java.io.InputStream; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources.NotFoundException; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; public class SkinResource { public static final String TAG = "SkinResource"; private static Context mSkinContext = null; private static Context mLocalContext = null; public static void initLocalContext(Context context) { mLocalContext = context; } public static void initSkinContext(Context context) { mSkinContext = context; } public static Context getSkinContext() { return mSkinContext; } private static boolean existSkinContext() { return mSkinContext != null; } public static InputStream getSkinRawInputStream(String name) { int rawId = 0; if (existSkinContext()) { rawId = getIdentifier(name, "raw", mSkinContext); if (rawId == 0) { rawId = getIdentifier(name, "raw", mLocalContext); return mLocalContext.getResources().openRawResource(rawId); } else { return mSkinContext.getResources().openRawResource(rawId); } } else { rawId = getIdentifier(name, "raw", mLocalContext); return mLocalContext.getResources().openRawResource(rawId); } } public static View getSkinLayoutViewByName(String name) { View view = null; if (existSkinContext()) {// 存在皮肤资源包 view = loadSkinLayoutView(name, mSkinContext); if (view == null) { // 资源皮肤中找不到资源,则加载本地资源 view = loadSkinLayoutView(name, mLocalContext); } } else { view = loadSkinLayoutView(name, mLocalContext); } return view; } public static int getSkinLayoutIdByName(String name, String type) { return getSkinResourceId(name, type); } public static String getSkinStringByName(String name) { String value = null; if (existSkinContext()) { value = loadSkinString(getIdentifier(name, "string", mSkinContext), mSkinContext); if (value == null) { value = loadSkinString( getIdentifier(name, "string", mLocalContext), mLocalContext); } } else { value = loadSkinString( getIdentifier(name, "string", mLocalContext), mLocalContext); } return value; } public static Drawable getSkinDrawableByName(String name) { Context context = mSkinContext; int id = getIdentifier(name, "drawable", context); if (id == 0 && mSkinContext != mLocalContext) { context = mLocalContext; id = getIdentifier(name, "drawable", context); } if (id == 0) { return null; } return context.getResources().getDrawable(id); } public static Drawable getSkinDrawableByName(String name, String type) { Drawable drawable = null; if (existSkinContext()) { drawable = loadSkinDrawable( getIdentifier(name, type, mSkinContext), mSkinContext); if (drawable == null) { drawable = loadSkinDrawable( getIdentifier(name, type, mLocalContext), mLocalContext); } } else { drawable = loadSkinDrawable( getIdentifier(name, type, mLocalContext), mLocalContext); } return drawable; } public static int getSkinResourceId(String name, String type) { int layoutId = 0; if (existSkinContext()) { layoutId = getIdentifier(name, type, mSkinContext); if (layoutId == 0) { layoutId = getIdentifier(name, type, mLocalContext); } } else { layoutId = getIdentifier(name, type, mLocalContext); } return layoutId; } public static ColorStateList getSkinColorStateList(String name) { ColorStateList colorStateList = null; if (existSkinContext()) { colorStateList = loadSkinColorStateList( getIdentifier(name, "drawable", mSkinContext), mSkinContext); if (colorStateList == null) { colorStateList = loadSkinColorStateList( getIdentifier(name, "drawable", mLocalContext), mLocalContext); } } else { colorStateList = loadSkinColorStateList( getIdentifier(name, "drawable", mLocalContext), mLocalContext); } return colorStateList; } public static int getSkinColorByName(String name) { int color = 0; if (existSkinContext()) { color = loadSkinColor(getIdentifier(name, "color", mSkinContext), mSkinContext); if (color == 0) { color = loadSkinColor( getIdentifier(name, "color", mLocalContext), mLocalContext); } } else { color = loadSkinColor(getIdentifier(name, "color", mLocalContext), mLocalContext); } return color; } private static int loadSkinColor(int id, Context context) { try { return context.getResources().getColor(id); } catch (NotFoundException e) { e.printStackTrace(); return 0; } } private static int getIdentifier(String name, String type, Context context) { try { return context.getResources().getIdentifier(name, type, context.getPackageName()); } catch (Exception e) { e.printStackTrace(); return 0; } } private static String loadSkinString(int id, Context context) { try { return context.getResources().getString(id); } catch (NotFoundException e) { e.printStackTrace(); return null; } } private static Drawable loadSkinDrawable(int id, Context context) { try { return context.getResources().getDrawable(id); } catch (NotFoundException e) { e.printStackTrace(); return null; } } private static ColorStateList loadSkinColorStateList(int id, Context context) { try { return context.getResources().getColorStateList(id); } catch (NotFoundException e) { e.printStackTrace(); return null; } } private static View loadSkinLayoutView(String name, Context context) { LayoutInflater layoutInflater = LayoutInflater.from(context); try { return layoutInflater.inflate( context.getResources().getLayout( getIdentifier(name, "layout", context)), null); } catch (NotFoundException e) { e.printStackTrace(); return null; } } public static String[] getSKinStringArraysByName(String name, String type) { String[] array = null; if (existSkinContext()) { array = mSkinContext.getResources().getStringArray( getIdentifier(name, type, mSkinContext)); if (array == null) { array = mLocalContext.getResources().getStringArray( getIdentifier(name, type, mLocalContext)); } } else { array = mLocalContext.getResources().getStringArray( getIdentifier(name, type, mLocalContext)); } return array; } }
2.因为本地资源和资源包虽然使用同个id号,但是使用的是不同的R文件,所以直接使用findViewById()的方式必然报空指针异常,所以这里用了另一种方式:设tag的方式:
这里的VTAG.java专门拿来放空间的tag:
public class VTAG { public static final String BUTTON_BACK = "btn_back"; public static final String TEXTVIEW_TEST = "textView_test"; public static final String IMAGEVIEW_TEST = "imageView_test"; public static final String BUTTON_ONE = "btn_one"; public static final String BUTTON_TWO = "btn_two"; public static final String TEXTVIEW_DEMO = "tv_demo"; public static final String EDITTEXT_DEMO = "et_demo"; public static final String ERR_VIEW = "err_view"; }
当然id不起作用了,所以布局是这样写的(只截取一段):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_blue_light" android:orientation="vertical" > <Button android:id="@+id/back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@drawable/flybtn_back" android:paddingTop="40px" android:tag="btn_back" android:text="返回" android:textColor="#FFFFFF" android:textSize="10sp" />
......................................................
</LinearLayout>
3.一个应用怎么跟皮肤资源包进行关联呢?这个当然少不了资源包的包名,所以将此块代码部分放在自定义的MyApplication里,具体如下:
public class MyApplication extends Application { public Context mContext; public Context mSkinContext; @Override public void onCreate() { super.onCreate(); initSkinResource(); } private void initSkinResource() { try { mSkinContext = createPackageContext("com.jrue.skin", Context.CONTEXT_IGNORE_SECURITY); } catch (NameNotFoundException e) { e.printStackTrace(); mSkinContext = this; } SkinResource.initLocalContext(this); SkinResource.initSkinContext(mSkinContext); } }其中下面的就是我们资源包的应用包名了。
com.jrue.skin
---------------------------------------------------------------------------分隔线补上补上---------------------------------------------------------------------------------------------------------------------------
突然发现有更好的方式写SkinResource方法,差点忘了,之前的也不删了,同样有用,但是觉得下面的会更有效,用法基本一样,不讲解,直接上代码:
SkinResoure另一种写法:
public class Skinresource { //tang 换皮肤 public static Context skinContext =null; public static Context mContext=null; public static void SetContext(Context context) { mContext = context; } public static void setSkinContext(Context context) { mContext = context; } /** * tang 换皮肤 获取各种资源 * @param skinPackageContext * @param resourceType * @param resourceName * @param packgeName * @return */ private static int getgetResourcesFromSkin(Context skinPackageContext,String resourceType, String resourceName,String packgeName) { int id=0; try { id=skinPackageContext.getResources().getIdentifier(resourceName, resourceType, packgeName); } catch(Exception e) { id=0; } return id; } /** * tang 取得皮肤包中的字符串 * @param skinPackageContext * @param resourceName * @return */ public static String getStringFromSkin(Context skinPackageContext,String resourceName) { int id=getgetResourcesFromSkin(skinPackageContext,"string", resourceName,"com.flyaudio.systemui_skin"); if(id==0) { id=getgetResourcesFromSkin(mContext,"string",resourceName,"com.android.systemui"); return mContext.getResources().getString(id); } return skinPackageContext.getResources().getString(id); } /** * tang 取得皮肤包中整型参数 * @param skinPackageContext * @param resourceName * @return */ public static Integer getIntegerFromSkin(Context skinPackageContext,String resourceName) { int id=getgetResourcesFromSkin(skinPackageContext,"integer", resourceName,"com.flyaudio.systemui_skin"); if(id==0) { id=getgetResourcesFromSkin(mContext,"integer",resourceName,"com.android.systemui"); return mContext.getResources().getInteger(id); } return skinPackageContext.getResources().getInteger(id); } /** * tang 取得皮肤包中Drawable资源 * @param skinPackageContext * @param resourceName * @return */ public static Drawable getDrawableFromSkin(Context skinPackageContext,String resourceName) { int id =getgetResourcesFromSkin(skinPackageContext,"drawable", resourceName,"com.flyaudio.systemui_skin"); if(id==0) { id=getgetResourcesFromSkin(mContext,"drawable",resourceName,"com.android.systemui"); return mContext.getResources().getDrawable(id); } return skinPackageContext.getResources().getDrawable(id); } public static ColorStateList getColorStateListFromSkin(Context skinPackageContext,String resourceName) { int id =getgetResourcesFromSkin(skinPackageContext,"drawable", resourceName,"com.flyaudio.systemui_skin"); if(id==0) { id=getgetResourcesFromSkin(mContext,"drawable",resourceName,"com.android.systemui"); return mContext.getResources().getColorStateList(id); } return skinPackageContext.getResources().getColorStateList(id); } /** * tang 取得皮肤包中color资源 * @param skinPackageContext * @param resourceName * @return */ public static int getColorFromSkin(Context skinPackageContext,String resourceName) { int id =getgetResourcesFromSkin(skinPackageContext,"color", resourceName,"com.flyaudio.systemui_skin"); if(id==0) { id=getgetResourcesFromSkin(mContext,"color",resourceName,"com.android.systemui"); return mContext.getResources().getColor(id); } return skinPackageContext.getResources().getColor(id); } /** * tang 取得皮肤包中layout资源 * @param skinPackageContext * @param resourceName * @return */ public static View getLayoutFromSkin(Context skinPackageContext,String resourceName) { int viewId=getgetResourcesFromSkin(skinPackageContext,"layout", resourceName,"com.flyaudio.systemui_skin"); LayoutInflater inflater=null; View view=null; Log.d("recy","getLayoutFromSkin "+viewId+""); if(viewId !=0) { inflater = LayoutInflater.from(skinPackageContext); view =inflater.inflate(skinPackageContext.getResources().getLayout(viewId), null); } else { viewId=getgetResourcesFromSkin(mContext,"layout",resourceName,"com.android.systemui"); inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view =inflater.inflate(mContext.getResources().getLayout(viewId), null); } return view; } /** * 取得皮肤包中ID * @param skinPackageContext * @param resourceName * @return */ public static int getIdFromSkin(Context skinPackageContext,String resourceName,String type) { int id=0; id=getgetResourcesFromSkin(skinPackageContext,type, resourceName,"com.flyaudio.systemui_skin"); Log.d("recy","getIdFromSkin "+id+""); if(id==0) { id=getgetResourcesFromSkin(mContext,type,resourceName,"com.android.systemui"); } return id; } }
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
然后大体代码的实现就这样了,资源包里的内容和布局也差不多,具体需要看最后的demo吧。demo地址下载
版权声明:本文为博主原创文章,未经博主允许不得转载。