经过SkinResource实现的应用皮肤动态识别切换

通过SkinResource实现的应用皮肤动态识别切换

   之前在公司的项目中,需要用到的需求是这样的,当一个应用开启时先去检测是否有对应的资源包(也是个APK,但是没有界面也就是Activity存在,只是单纯的资源),如果有则加载资源包里面的资源,没有的话则加载本身的资源。这样的好处是什么呢?就是以后要修改资源布局的时候,只要改资源包里对应的东西,然后将新的资源包加载进系统就行了,而不用每次都要改本身的应用。大大方便了后续的开发和维护。今天趁着不用加班,有空的时间,整理了一下,不过一个多星期的东西了,凭记忆书写,不知道会不会漏了某些知识点,也在最后放上一个多星期前自己学习用的demo,到时用的时候可以先导入demo的应用apk,再导入皮肤包的apk,这样就能体会到差别了。

   无图无真相,先来两张图作对比(第一张是用本应用的资源,第二张是导入了资源包调用资源包里的资源)

经过SkinResource实现的应用皮肤动态识别切换          经过SkinResource实现的应用皮肤动态识别切换

   废话不多说,直接用代码说话:

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地址下载

    


版权声明:本文为博主原创文章,未经博主允许不得转载。