Android学习之 换肤功能模块的实现<二>

但使书种多,会有岁稔时。这篇文章主要讲述Android学习之 换肤功能模块的实现& lt; 二& gt; 相关的知识,希望能为你提供帮助。
    在上篇中 主要有学习到皮肤资源内置到应用程序中 的方式实现换肤的 基本思路,本篇将继续以上篇的思路学习 皮肤资源内置的方式实现换肤效果、但本篇側重于应用中换肤功能的代码设计实现上。切换的皮肤资源位于assets下不同的皮肤资源目录中。
    本篇demo程序的代码结构例如以下:
     

Android学习之 换肤功能模块的实现<二>
本篇实现换肤功能的代码设计 UML类图例如以下:
Android学习之 换肤功能模块的实现<二>

文章图片


本篇demo的换肤效果例如以下:
Android学习之 换肤功能模块的实现<二>

文章图片
       
Android学习之 换肤功能模块的实现<二>

文章图片




Android学习之 换肤功能模块的实现<二>        Android学习之 换肤功能模块的实现<二>



基本的实现代码在于:
1、SkinConfigManager.java  
作用:皮肤配置管理。封装了SharedPreferences对选择皮肤的序号储存、以及依据皮肤类型锁定assets下的皮肤资源。
具体代码例如以下:

package com.ice.skininnerdemo; import android.content.Context; import android.content.SharedPreferences; /** * 皮肤配置管理< 单例> < /br> * 封装了 SharedPreferences 对象的储存操作 * Created by ice on 14-10-9. */ public class SkinConfigManager {private static SkinConfigManager mSkinConfigManager; public static final String SKINCONFIG = " SkinConfig" ; public static final String CURSKINTYPEKEY = " curSkinTypeKey" ; private static SharedPreferences mSharedPreferences; private SkinConfigManager(Context context){ mSharedPreferences = context.getSharedPreferences(SKINCONFIG, 0); }public synchronized static SkinConfigManager getInstance(Context context) { if (mSkinConfigManager == null) { mSkinConfigManager = new SkinConfigManager(context); } return mSkinConfigManager; }/** * 设置储存当前选择的皮肤类型值(int 类型值)到 SharedPreferences * @param skinType皮肤类型 */ public void setCurSkinType(int skinType){ SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putInt(CURSKINTYPEKEY, skinType); editor.commit(); }/** * 获得当前储存在SharedPreferences中的 当前皮肤类型< CURSKINTYPE> 值 * @return */ public int getCurSkinType(){ if (mSharedPreferences != null) { return mSharedPreferences.getInt(CURSKINTYPEKEY, 0); } return 0; }/** * 获得assets目录以下当前皮肤资源所相应的皮肤目录名 * @return */ public String getSkinFileName () { String skinFileName = null; switch (getCurSkinType()){ case 0: // 默认的皮肤类型 break; case 1: skinFileName = " skin_blue" ; break; case 2: skinFileName = " skin_orange" ; break; case 3: skinFileName = " skin_red" ; break; } return skinFileName; }public SharedPreferences getSkinConfigPreferences () { return mSharedPreferences; } }


2、SkinManager.java     【Android学习之 换肤功能模块的实现& lt; 二& gt; 】
作用:皮肤资源管理器。用于获取assets文件下不同皮肤类型的图片资源文件
具体代码例如以下:

package com.ice.skininnerdemo; import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import java.io.IOException; import java.io.InputStream; /** * Created by ice on 14-10-8. * 皮肤资源管理器< 单例> */ public class SkinManager {private static SkinManager mSkinManager; private AssetManager mAssetManager; private SkinManager (Context context) { this.mAssetManager = context.getAssets(); }public synchronized static SkinManager getInstance(Context context){if (mSkinManager == null) { mSkinManager = new SkinManager(context); } return mSkinManager; }/** * 依据皮肤文件名称 和 资源文件名称 获取Assets 里面的皮肤资源Drawable对象 * @param skinFileName皮肤文件名称 * @param fileName资源文件名称 * @return */ public Drawable getSkinDrawable(String skinFileName, String fileName) { Drawable drawable = null; try { InputStream inputStream = mAssetManager.open(skinFileName + " /" + fileName); drawable = Drawable.createFromStream(inputStream, null); } catch (IOException e) { e.printStackTrace(); }return drawable; }/** * 依据皮肤文件名称 和 资源文件名称 获取Assets 里面的皮肤资源Bitmap对象 * @param skinFileName * @param fileName * @return */ public Bitmap getSkinBitmap(String skinFileName, String fileName){ Bitmap image = null; try { InputStream inputStream = mAssetManager.open(skinFileName + " /" + fileName); image = BitmapFactory.decodeStream(inputStream); } catch (IOException e) { e.printStackTrace(); }return image; }}


3、SkinableActivity.java 
作用:换肤Activity抽象类,假设说应用中某个Activiy有换肤的需求,那么就继承SkinableActivity吧。
它主要实现了OnSharedPreferenceChangeListener 监听接口,而且注冊了SharedPreferences内容改变的事件监听。
在监听到SharedPreferences发生改变的同一时候回调changeSkin()抽象方法。该方法由SkinableActivity的子类详细实现UI上皮肤资源的更换。
具体代码例如以下:

package com.ice.skininnerdemo; import android.app.Activity; import android.content.SharedPreferences; /** * 换肤Activity抽象类 * Created by ice on 14-10-8. */ public abstract class SkinableActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener{@Override protected void onStart() { super.onStart(); initSkin(); }/** *初始化皮肤 */ private void initSkin() { changeSkin(); // 注冊监听。监听换肤的通知 SkinConfigManager.getInstance(this).getSkinConfigPreferences() .registerOnSharedPreferenceChangeListener(this); }/** * sharedPreferences 内容发生改变时触发 * @param sharedPreferences * @param key sharedPreferences中的key值 */ @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (SkinConfigManager.CURSKINTYPEKEY.equals(key)) { changeSkin(); } }@Override protected void onStop() { super.onStop(); SkinConfigManager.getInstance(this).getSkinConfigPreferences() .unregisterOnSharedPreferenceChangeListener(this); }/** * 更改设置皮肤,SkinableActivity子类必需要实现该方法 完毕换肤过程 */ protected abstract void changeSkin(); }


4、SkinSettingActivity.java
作用:皮肤设置Activity,继承了SkinableActivity,实现了changeSkin()抽象方法,完毕了皮肤设置UI上的皮肤更换。
(应用中其它须要换肤的Activity类似 、主要在changeSkin()方法中实现界面的换肤需求)
具体代码例如以下:

package com.ice.skininnerdemo; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.GridView; import android.widget.SimpleAdapter; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * 皮肤设置Activity * Created by ice on 14-10-10. */ public class SkinSettingActivity extends SkinableActivity{private static final String TAG = " SkinSettingActivity" ; private GridView gv_skin_type; private TextView tv_skin_cur; private TextView tv_title_skin_setting; private int[] skinTypeImage = new int[]{ R.drawable.overview_skin_default, R.drawable.overview_skin_blue, R.drawable.overview_skin_orange, R.drawable.overview_skin_red }; private int[] skinTypeName = new int[]{ R.string.skin_default, R.string.skin_blue, R.string.skin_orange, R.string.skin_red }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_skin_setting); initView(); bindEvent(); }private void initView() { tv_title_skin_setting = (TextView)findViewById(R.id.tv_title_skin_setting); tv_skin_cur = (TextView)findViewById(R.id.tv_skin_cur); gv_skin_type = (GridView)findViewById(R.id.gv_skin_type); setGridViewAdapter(gv_skin_type); }private void setGridViewAdapter(GridView mGridView) { List< HashMap< String, Object> > data = https://www.songbingjia.com/android/new ArrayList< HashMap< String, Object> > (); int length = skinTypeImage.length; for(int i=0; i< length; i++){ HashMap< String,Object> map = new HashMap< String, Object> (); map.put(" skinTypeImage" , skinTypeImage[i]); map.put(" skinTypeName" , getString(skinTypeName[i])); data.add(map); }SimpleAdapter simpleAdapter = new SimpleAdapter( this, data, R.layout.traffic_item, new String[]{" skinTypeImage" , " skinTypeName" }, new int[]{R.id.iv_traffic, R.id.tv_trafficName}); mGridView.setAdapter(simpleAdapter); }private void bindEvent() { gv_skin_type.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView< ?> adapterView, View view, int i, long l) { tv_skin_cur.setText(skinTypeName[i]); // 将当前选择的皮肤相应的序号 储存到 SharedPreferences 中 SkinConfigManager.getInstance(SkinSettingActivity.this).setCurSkinType(i); } }); }@Override protected void changeSkin() { SkinConfigManager mSkinConfigManager = SkinConfigManager.getInstance(SkinSettingActivity.this); String skinFileName = mSkinConfigManager.getSkinFileName(); Log.d(TAG, " changeSkin() 被运行 / skinFileName: " + skinFileName); // 获取当前正在使用的皮肤序号 int skinType = mSkinConfigManager.getCurSkinType(); tv_skin_cur.setText(skinTypeName[skinType]); if(skinFileName != null){ Drawable drawable = SkinManager.getInstance(this).getSkinDrawable(skinFileName, " bg_title.9.png" ); tv_title_skin_setting.setBackground(drawable); } else { tv_title_skin_setting.setBackgroundResource(R.drawable.bg_title); } }}





-- -- ok、本篇demo实现换肤效果的主要代码、设计思路于此!小吕事实上还想过第二种皮肤资源的配置方式。
大体想法例如以下:
1、在assets文件下以下新建一个皮肤资源的配置文件 如:skin.properties 或是 skin_configure.xml
2、全部的皮肤资源(图片)将会放在res/drawable/以下,而什么皮肤类型所相应的皮肤资源图片将会在1中的skin.properties 或是  skin_configure.xml中 通过配置的方式引用。



当然   这仅仅是小吕眼下的一个初步想法及设计思想、假设 看到这里的您 假设还有其它实现换肤的设计思想、还希望大气的给小吕留言、学习、和交流。



补充内容:本demo中 有关于获取assets文件里的.9格 式图片。

                    关于获取assets以下的.9格 式图片问题,这里是非常有趣的。
                    该demo中assets下的.9格 式图片 都是先使用 AAPT 命令编译处理后的,及被Android系统编译过的。
                    那为什么要这样做呢?大家能够先自己研究下 或是 在网上搜索答案、小吕后面有时间将会整理成博客。



最后附上本篇demo的代码< 免下载积分> :  http://download.csdn.net/detail/l416112167/8027581
-----------------
下篇   小吕将会学习与介绍另外一种实现方式:   [皮肤资源与应用程序分离]

























    推荐阅读