在上篇中 主要有学习到皮肤资源内置到应用程序中 的方式实现换肤的 基本思路,本篇将继续以上篇的思路学习 皮肤资源内置的方式实现换肤效果、但本篇側重于应用中换肤功能的代码设计实现上。切换的皮肤资源位于assets下不同的皮肤资源目录中。
本篇demo程序的代码结构例如以下:
本篇实现换肤功能的代码设计 UML类图例如以下:
本篇demo的换肤效果例如以下:
基本的实现代码在于:
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;
}
}
作用:皮肤资源管理器。用于获取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;
}
}
作用:换肤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();
}
作用:皮肤设置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 = 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
-----------------
下篇 小吕将会学习与介绍另外一种实现方式: [皮肤资源与应用程序分离]
原文:http://www.cnblogs.com/jzdwajue/p/7181954.html