本篇博客要给大家分享的一个关于Android应用换肤的Demo,大家可以到我的github去下载demo,以后博文涉及到的代码均会上传到github中统一管理。

github地址:https://github.com/devilWwj/Android-skin-update

思路

换肤功能一般有什么?
元素一般有背景颜色、字体颜色、图片、布局等等

我们知道Android中有主题Theme还有style,theme是针对整个activity的,而style可以针对指定控件,如果比较少的替换可以在app内做,但如果需要动态来做,可以选择下面这种思路:

把app和skin分开,将skin做成一个apk,作为一个插件来提供给app使用,这样可以做到在线下载皮肤,然后动态更换皮肤

下面这个demo,小巫是建立了一个res的工程项目,简单提供了一个colors.xml,在里面指定了背景颜色和按钮颜色:

<?xml version="1.0" encoding="utf-8"?>
<resources><color name="day_btn_color">#E61ABD</color><color name="day_background">#38F709</color><color name="night_btn_color">#000000</color><color name="night_background">#FFFFFF</color>
</resources>

里面没有任何逻辑代码,只提供资源文件,然后我们导出为skin.apk文件,复制到目标项目的assets中去。

因为这里不涉及到下载皮肤这个操作,所以直接放到assets目录下,然后在程序中把assets下的apk文件复制到sd卡中.
在程序中提供一个皮肤包管理器

package com.devilwwj.skin;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.AsyncTask;/*** 皮肤包管理器* * @author devilwwj* */
public class SkinPackageManager {private static SkinPackageManager mInstance;private Context mContext;/*** 当前资源包名*/public String mPackageName;/*** 皮肤资源*/public Resources mResources;public SkinPackageManager(Context mContext) {super();this.mContext = mContext;}/*** 获取单例* * @param mContext* @return*/public static SkinPackageManager getInstance(Context mContext) {if (mInstance == null) {mInstance = new SkinPackageManager(mContext);}return mInstance;}/*** 从assets中复制apk到sd中* * @param context* @param filename* @param path* @return*/public boolean copyApkFromAssets(Context context, String filename,String path) {boolean copyIsFinish = false;try {// 打开assets的输入流InputStream is = context.getAssets().open(filename);File file = new File(path);// 创建一个新的文件file.createNewFile();FileOutputStream fos = new FileOutputStream(file);byte[] temp = new byte[1024];int i = 0;while ((i = is.read(temp)) > 0) {fos.write(temp, 0, i); // 写入到文件}fos.close();is.close();copyIsFinish = true;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return copyIsFinish;}/*** 异步加载皮肤资源* * @param dexPath*            需要加载的皮肤资源* @param callback*            回调接口*/public void loadSkinAsync(String dexPath, final loadSkinCallBack callback) {new AsyncTask<String, Void, Resources>() {@Overrideprotected void onPreExecute() {super.onPreExecute();if (callback != null) {callback.startloadSkin();}}@Overrideprotected Resources doInBackground(String... params) {try {if (params.length == 1) {//String dexPath_tmp = params[0];// 得到包管理器PackageManager mpm = mContext.getPackageManager();// 得到包信息PackageInfo mInfo = mpm.getPackageArchiveInfo(dexPath_tmp, PackageManager.GET_ACTIVITIES);mPackageName = mInfo.packageName;// AssetManager实例AssetManager assetManager = AssetManager.class.newInstance();// 通过反射调用addAssetPath方法Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);addAssetPath.invoke(assetManager, dexPath_tmp);// 得到资源实例Resources superRes = mContext.getResources();// 实例化皮肤资源Resources skinResource = new Resources(assetManager,superRes.getDisplayMetrics(),superRes.getConfiguration());// 保存资源路径SkinConfig.getInstance(mContext).setSkinResourcePath(dexPath_tmp);return skinResource;}} catch (Exception e) {return null;}return null;}@Overrideprotected void onPostExecute(Resources result) {super.onPostExecute(result);mResources = result;// 这里执行回调方法if (callback != null) {if (mResources != null) {callback.loadSkinSuccess();} else {callback.loadSkinFail();}}}}.execute(dexPath);}public static interface loadSkinCallBack {public void startloadSkin();public void loadSkinSuccess();public void loadSkinFail();}}

重点关注这个类,里面提供了一个异步方法对包和asset进行操作,这里用到了反射机制,反射调用addAssetPath来添加assets的路径,这个路径就是我们skin.apk的路径。具体细节,各位查看代码。

我们在Activity界面中使用上面提供的方法:

package com.devilwwj.skin;import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;import com.devilwwj.skin.SkinPackageManager.loadSkinCallBack;
/*** 功能:切换皮肤* @author devilwwj**/
public class MainActivity extends Activity implements OnClickListener,ISkinUpdate {private static final String APK_NAME = "skin.apk";private static final String DEX_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/skin.apk";private Button dayButton;private Button nightButton;private TextView textView;private boolean nightModel = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);dayButton = (Button) findViewById(R.id.btn_day);nightButton = (Button) findViewById(R.id.btn_night);textView = (TextView) findViewById(R.id.text);// 把apk文件复制到sd卡SkinPackageManager.getInstance(this).copyApkFromAssets(this, APK_NAME,DEX_PATH);}@Overrideprotected void onResume() {super.onResume();if (SkinPackageManager.getInstance(this).mResources != null) {updateTheme();}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_day:nightModel = false;loadSkin();break;case R.id.btn_night:nightModel = true;loadSkin();break;default:break;}}/*** 加载皮肤*/private void loadSkin() {SkinPackageManager.getInstance(this).loadSkinAsync(DEX_PATH,new loadSkinCallBack() {@Overridepublic void startloadSkin() {Log.d("xiaowu", "startloadSkin");}@Overridepublic void loadSkinSuccess() {Log.d("xiaowu", "loadSkinSuccess");// 然后这里更新主题updateTheme();}@Overridepublic void loadSkinFail() {Log.d("xiaowu", "loadSkinFail");}});}@Overridepublic void updateTheme() {Resources mResource = SkinPackageManager.getInstance(this).mResources;if (nightModel) {// 如果是黑夜的模式,则加载黑夜的主题int id1 = mResource.getIdentifier("night_btn_color", "color","com.devilwwj.res");nightButton.setBackgroundColor(mResource.getColor(id1));int id2 = mResource.getIdentifier("night_background", "color","com.devilwwj.res");nightButton.setTextColor(mResource.getColor(id2));textView.setTextColor(mResource.getColor(id2));} else {// 如果是白天模式,则加载白天的主题int id1 = mResource.getIdentifier("day_btn_color", "color","com.devilwwj.res");dayButton.setBackgroundColor(mResource.getColor(id1));int id2 = mResource.getIdentifier("day_background", "color","com.devilwwj.res");dayButton.setTextColor(mResource.getColor(id2));textView.setTextColor(mResource.getColor(id2));}}}

我们可以保存一个模式,比如黑夜白天模式,每次启动按照前面保存的模式来显示皮肤。我们可以看到上面是通过调用getIdentifier方法来得到指定的资源的id,name是我们在资源文件中指定的名字。

最后,各位自己跑一遍这样的流程:

1. 导出res的apk文件
2. 复制到目标项目的assets目录下
3. 查看切换皮肤的效果

参考博文:http://blog.csdn.net/yuanzeyao/article/details/42390431

Android 更换皮肤思路及解决方案相关推荐

  1. android换皮肤思路总结

       前段时间公司有做换皮肤的项目,经过网上搜罗,查看资料,我个人总结三种换皮肤的方法.     网上说的最多的就是使用android:sharedUserId标签来共享资源,但是经我测试无论用不用这 ...

  2. 轻松实现Android 更换皮肤(主题)

    目前很多app都具有换肤功能,可以根据用户自己的喜好定制自己的界面,比如新浪微博,网易新闻等等.今天这里我就是要介绍一种机制实现app换肤. 我找了几款app换肤的应用,换肤基本都是更换了界面的Ico ...

  3. android 更换皮肤项目

    android换肤项目是本人学习android不到一个月做的第一个项目,所以有很多可以优化的地方,仅给大家提供一个参考. package wang.sc; import android.app.Act ...

  4. apk分享: Android应用更换皮肤功能的实现思路教程。

    Android 的发展确实太快了,每年的都有很多新东西出现,想要覆盖所有新东西感觉也不太可能,我这里主要说一下主要的 Android 的主要新技术发展,其实了解 Android 的发展趋势,可能对开发 ...

  5. [转载]Android实现更换皮肤功能

    原文地址:Android实现更换皮肤功能作者:兜兜 转载请注明出处,商用请与本人联系. 本系列专题培训适用范围:初级Android程序员,即有J2SE基础和Android初级水平.J2SE基础是指掌握 ...

  6. android应用换肤功能,如何给Android应用更换皮肤

    Android应用更换皮肤功能的实现思路 我们可以将皮肤包做成一个apk文件,在应用apk中读取皮肤包中的数据. 应用apk读取皮肤包apk的数据的条件 1. 有相同签名 2. AndroidMani ...

  7. android+自定义皮肤,android studio自定义更换皮肤详细图文教程

    android studio这款app程序开发软件内也内置了多种皮肤主题,程序开发人员如果感觉一种皮肤太过单调乏味,可以选择使用软件内的其他皮肤风格,软件默认的皮肤是IntelliJ,还有黑色的Dra ...

  8. android 自定义皮肤,仿墨迹天气在Android App中实现自定义zip皮肤更换

    在这里谈一下墨迹天气的换肤实现方式,不过首先声明我只是通过反编译以及参考了一些网上其他资料的方式推测出的换肤原理, 在这里只供参考. 若大家有更好的方式, 欢迎交流. 墨迹天气下载的皮肤就是一个zip ...

  9. Android大图片裁剪终极解决方案 原理分析

    约几个月前,我正为公司的APP在Android手机上实现拍照截图而烦恼不已. 上网搜索,确实有不少的例子,大多都是抄来抄去,而且水平多半处于demo的样子,可以用来讲解知识点,但是一碰到实际项目,就漏 ...

  10. C#如何使用skinEngine控件换肤(更换皮肤)?

    在使用C#开发窗体程序时,原始的皮肤方案比较难看,因此开发者需要更换皮肤,以提高客户体验.skinEngine控件就是一个很好的解决方案,它可以降低开发者开发新皮肤的成本,一个新手也可以很快的掌握更换 ...

最新文章

  1. 使用Oracle创建图书馆数据库
  2. SQLServer之修改FOREIGN KEY约束
  3. Linux系统管理命令:date、free、ps、du、kill、uname
  4. Ubuntu kylin 14.04 LTS上安装opencv
  5. 爬取IMDBTOP250
  6. 题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】
  7. .net 读取xml文件
  8. 滴滴再曝收费不靠谱:去程19元 回时164.8元
  9. 数据库系统原理——概述
  10. Struts2框架的概念及使用方法
  11. 针对单个网站的渗透思路(精)
  12. Android dev 设备访问权限 777,Android Studio:/ dev / kvm设备权限被拒绝
  13. 联想k50+开发者模式+linux,联想 K50-T5中文Recovery刷机教程
  14. python实现五大基本算法语句_python实现各种最优化算法
  15. 宿命论與自由意志 ---霍金
  16. 《C++精英内参之程序员高效指南》-12-8影响效率的不良习惯之科学的休息方法
  17. 探索人群客单价差异的显著性,使用SPSS就能轻松做到
  18. 【转】本人常用资源整理
  19. Suzy找到实习了吗Day 10 | 栈和队列开始啦:232. 用栈实现队列,225. 用队列实现栈
  20. 关于Caused by: com.alibaba.fastjson.JSONException: syntax error, expect }, actual ,

热门文章

  1. 教育知识与能力-第七章 中学德育
  2. 《Java编程培训教程》
  3. NYOJ-47 过河问题
  4. css background动态图片,CSS3 background-position定位背景图片动画效果
  5. 【云速建站】如何实现多用户权限管理
  6. 带你开发一款给Apk中自动注入代码工具icodetools(完善篇)
  7. 【懒人神器,批量src】Serein,一个可以对无数个网站进行漏洞检测的软件
  8. SQL Server evaluation period has expired
  9. 解决异常redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  10. oppo小布机器人_OPPO小布助手2.0全新版本来袭,做你身边最聪明的AI语音助手