android app换肤详解
来源:互联网 发布:中行外汇分析软件 编辑:程序博客网 时间:2024/05/16 16:20
前言
现在很多APP中都会有换肤功能,看着很神奇,一键点击app大换样,那么这篇就来简单阐释一下换肤是如何实现的
效果图
图1
图2
换肤实现方式?
软件换肤从功能上可以划分三种:
1) 软件内置多个皮肤,不可由用户增加或修改;
最低的自由度,软件实现相对于后两种最容易。
2) 官方提供皮肤供下载,用户可以使用下载的皮肤;
用户可选择下载自己喜欢的皮肤,有些玩家会破解皮肤的定制方法,自己做皮肤使用,或者传到网上给大家用。
3) 官方提供皮肤制作工具或方法,用户可自制皮肤。
这种方式使用户有参与感,自由度较高。用户可根据自己的喜好定制软件的皮肤。有些软件官网提供皮肤定制的工具或者方法,我建议最好有可视化带向导的工具。用户只要自己找一些图片、修改文字的字体替换就可以了。用户可以上传自制的皮肤,提供其他用户下载,还可以赚得一些虚拟货币或者奖品什么的。这种一般都是打包为.zip格式的。扩展名可由各公司自定义,有制作工具的话直接导出来最方便。
首先我们要弄清楚换肤的定义,软件皮肤包括图标、字体、布局、交互风格等,换肤就是换掉皮肤包括的部分或所有资源。
前面提到的三种皮肤,从软件实现上来看,它们的本质区别是皮肤是否内置到应用程序中。对于内置的实现比较简单,只要在开发应用的过程中设计几套皮肤供用户选择。这里用到的知识不超过Android基础,不详细讲解。
这里主要介绍外置方式
采用压缩包方式(zip/apk)
首先需要了解Context原理,android资源管理机制分析,这两篇blog
换肤分为几个步骤
1.触发换肤逻辑
2.提前下载/触发时下载 皮肤资源包(apk,zip)
3.使用AssetManager创建 皮肤资源包Resource 对象
4.通知宿主app进行换肤动作。(需提前收集需要换肤的界面)
根据上面的步骤,写的demo
package com.nuoyuan.utils.changetheme;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;import com.nuoyuan.utils.base.SkinConfig;import java.lang.reflect.Method;/** * Author: weichyang * Date: 2017/10/12 * Description: 解析皮肤资源包 */public class SkinPackageManager { private static SkinPackageManager mInstance; private Context mContext; /** * 当前资源包名 */ public String mPackageName; /** * 皮肤资源 */ public Resources mResources; private SkinPackageManager(Context mContext) { this.mContext=mContext; } public static SkinPackageManager getInstance(Context mContext) { if(mInstance==null) { mInstance=new SkinPackageManager(mContext); } return mInstance; } /** * 异步加载皮肤资源 * @param dexPath * 需要加载的皮肤资源 * @param callback * 回调接口 */ public void loadSkinAsync(String dexPath,final loadSkinCallBack callback) { new AsyncTask<String,Void,Resources>() { protected void onPreExecute() { if(callback!=null) { callback.startloadSkin(); } }; @Override protected 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.class.newInstance(); 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; } return null; } catch (Exception e) { return null; } }; protected void onPostExecute(Resources result) { mResources=result; if(callback!=null) { if(mResources!=null) { callback.loadSkinSuccess(); }else { callback.loadSkinFail(); } } }; }.execute(dexPath); } /** * Author: weichyang * Date: 2017/1 * Description:加载资源的回调接口 */ public static interface loadSkinCallBack { public void startloadSkin(); public void loadSkinSuccess(); public void loadSkinFail(); } }
分析下核心代码
PackageManager mPm=mContext.getPackageManager(); PackageInfo mInfo=mPm.getPackageArchiveInfo(dexPath_tmp,PackageManager.GET_ACTIVITIES); mPackageName=mInfo.packageName; AssetManager assetManager = AssetManager.class.newInstance(); 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());
通过传递的资源apk 路径,用 PackageManager 获取到 资源apk 包名,因为 addAssetPath()为隐藏方法,采用反射进行调用,传递资源路径。然后拼装参数的构建皮肤资源apk的Resources 对象并设置为成员变量返回。
以上步骤就完成了 资源apk Resource的生成,有了Resources 也就有了调用资源文件的权限。
//进行主题更新 @Override public void updateTheme() { try { // 获取资源apk Resources对象 Resources mResource = SkinPackageManager.getInstance(this).mResources; //调用colors 方式 int id1 = mResource.getIdentifier("colorPrimary", "color", "theme.nydialog.com.theme"); btn_main.setBackgroundColor(mResource.getColor(id1)); int id2 = mResource.getIdentifier("colorPrimary", "color", "theme.nydialog.com.theme"); main_view.setBackgroundColor(mResource.getColor(id2));//调用图片资源,注意这里采用Drawable方式 linearLayout.setBackground(mResource.getDrawable(mResource.getIdentifier("bg", "drawable","theme.nydialog.com.theme"))); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
具体细节问题请查看
Nydialog https://github.com/yatou252303/Nydialog
引用
Android应用如何实现换肤功能
http://www.cnblogs.com/suiyc/archive/2011/05/27/2059778.html
- android app换肤详解
- Android App节日换肤
- android app换肤(更换主题)
- Android开发之APP换肤简介
- android自定义dialog实现app换肤功能
- Android开发之APP换肤简介(一)
- Android应用换肤
- android 换肤
- android 换肤
- Android换肤apk
- android 换肤 .
- Android应用换肤
- android换肤
- android换肤
- android换肤机制
- Android应用换肤
- android换肤实现
- Android换肤技术
- 每位程序员必读的书单
- 各国际会议的影响因子
- vmware 虚拟化Intel VT-x/EPT选项
- 4-20ma输出电路
- 工具:为GitHub 添加SSH-key简介
- android app换肤详解
- JAVA虚拟机的生命周期
- 【转载】电磁波中的波段划分:L波段、S波段、C波段、X波段、Ku波段、K波段、Ka波段 等等
- Fiori学习笔记
- Eclipse中SVN的使用
- 非root用户ssh不能登录本机
- Enhanced JMS Scheduler in ActiveMQ
- 如何从SEO到SEM的转化
- 框架整合----mybatis