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

在上篇中 主要有学习到皮肤资源内置到应用程序中 的方式实现换肤的 基本思路,本篇将继续以上篇的思路学习 皮肤资源内置的方式实现换肤效果、但本篇側重于应用中换肤功能的代码设计实现上。切换的皮肤资源位于assets下不同的皮肤资源目录中。

本篇demo程序的代码结构例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFuaWNlMDUyOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

本篇实现换肤功能的代码设计 UML类图例如以下:

本篇demo的换肤效果例如以下:

 
    

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFuaWNlMDUyOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="360" height="650" > 
    

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFuaWNlMDUyOQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="360" height="650" >

基本的实现代码在于:

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

作用:皮肤资源管理器。用于获取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 = 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

-----------------

下篇  小吕将会学习与介绍另外一种实现方式:  [皮肤资源与应用程序分离]

时间: 2024-10-12 08:59:33

Android学习之 换肤功能模块的实现&lt;二&gt;的相关文章

Android学习之 换肤功能模块的实现&lt;二&gt;

在上篇中 主要有学习到皮肤资源内置到应用程序中 的方式实现换肤的 基本思路,本篇将继续以上篇的思路学习 皮肤资源内置的方式实现换肤效果.但本篇侧重于应用中换肤功能的代码设计实现上!切换的皮肤资源位于assets下不同的皮肤资源文件夹中. 本篇demo程序的代码结构如下: 本篇实现换肤功能的代码设计 UML类图如下: 本篇demo的换肤效果如下:               主要的实现代码在于: 1.SkinConfigManager.java 作用:皮肤配置管理,封装了SharedPrefere

教程: Android应用如何实现换肤功能

本节课程的目的:学会换肤的方案及实现,掌握不同换肤方案的优缺点及适用场合. 希望各位同学做到:学习某一个技巧就掌握透彻,多练习.最好举一反三.触类旁通,掌握分析问题解决问题的思路和方法. 我讲解的是原理以及实现的关键技术点,细节.优化及与课程主题不相关的或初级的内容可能不会讲解.这是免费培训,精力有限,暂时只能做到让普通的变优秀,让优秀的变卓越.你要是已经卓越了来教教我吧.暂时不做入门培训. 国内有很多的软件都支持皮肤定制,这也是与国外软件重大不同之一,国外用户注重社交.邮件等功能,国内用户则重

Android实现换肤功能(一)

上周有个朋友给建议说讲讲换肤吧,真巧这周公司的工作安排也有这个需求,换的地方之多之繁,让人伤神死了.正所谓磨刀不误砍柴工,先磨下刀,抽出一个工具类,写了个关于换肤的简单demo. Android中换肤的实现有几种方法,我使用的是读取共享进程空间另一apk中的资源的方法.大致的原理如下,让你的app和一个只有资源文件的app运行在同一进程中,这样你的app就可以访问另一app的资源了.原理很简单,下面我们分步骤讲解实现过程. 一.共享进程运行的空间 通过在两个工程下的manifest根节点添加相同

Android实现换肤功能(二)

前两天写的上章关于换肤的功能获得了很好的反响,今天为大家介绍另一种方式.今天实现的策略也是网友建议的,然后我自己去写了个demo,大家自己评估下相比第一种方式的优势和劣势在哪里. 简单介绍下关于第一种关于换肤实现的方法一些不友好的地方,比如点击了换肤的功能键,需要先下载一个资源apk,然后再去引用其中的资源ID,于用户使用起来确实有有很多不便之处.今天为大家介绍的方法是克服了这一弊端的,可以实现直接在应用内切换,把资源文件存储在本地apk的,读取和操作也是更加便捷的,下面介绍下大致的一个实现逻辑

使用DevExpress实现界面换肤功能

最近要用到devExpress,一句话,很好很强大,比起vs自带的winform界面,种类和花样要多了不少,然而,强力的功能带来了庞大的信息量,所以我打算通过一些小模块来和大家一起对它进行探讨和研究. 今天先研究一下他的换肤功能.在控件中,其默认提供了18中风格让我们选择,如下图: 下面就看看怎么实现让界面切换到选中风格的功能.先建立一个项目,引入一个button和一个grid如下图: 由于在devExpress.skins.skinManager.Default.Skins中只有13中皮肤所以

实现系统滚动条换肤功能

http://blog.sina.com.cn/s/blog_4c3538470100gews.html 1 实现系统滚动条换肤功能 对于Windows系统中各种控件换肤功能,要数滚动条的换肤最难实现了,尤其是控件自带的系统滚动条,如Edit.ListBox.ListView.TreeView等自带的系统滚动条,要想实现其自定义的皮肤功能,用常规办法似乎都无法实现. 对于常规的皮肤定制一般都是通过定制WM_PAINT.WM_ERASEBKGND.WM_CTLCOLORxxx.NM_CUSTOMD

JS实现网页换肤功能

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JS实现网页换肤功能 -石家庄花卉出租 </ti

[转]页面换肤功能浅析

原理:通过存取cookie和dom操作调用不同的样式表文件来实现前台换肤. Html代码部分: 1.要有一个带id的样式表链接,我们要通过操作这个链接来调用不同的href. <link href="css/main0.css" rel="stylesheet" type="text/css" id="cssfile" /> 2.皮肤选择按钮(后台为每个li添加onclick事件,触发换肤功能) <ul id=

VS2010使用皮肤控件实现换肤功能

在我们平时使用的各种工具中,如QQ,迅雷,以及各种空间等,都提供了一些换肤功能,可以让我们选择各种我们喜欢的界面.本文就对VS中常用的窗口程序做一个简单的换肤,利用一个dll文件来进行实现. 首先我们要加载一个叫做IrisSkin2.dll的dll文件,通过“添加引用”,在应用里添加IrisSkin2.dll,就可以完成对这个dll的调用.然后在工具栏中添加一个SkinEngine的控件.可以在工具栏中添加一个选项卡,比如命名为Skin,然后右键单击,在选择项的.NETFramework组件中找