android换肤

来源:互联网 发布:epub转azw3软件 编辑:程序博客网 时间:2024/05/22 13:14

方式一、


国内有很多的软件都支持皮肤定制,这也是与国外软件重大不同之一,国外用户注重社交、邮件等功能,国内用户则重视音乐、小说、皮肤等功能,本节课程就来讲解Android应用程序如何实现换肤功能。
软件换肤从功能上可以划分三种:
  1) 软件内置多个皮肤,不可由用户增加或修改;
    最低的自由度,软件实现相对于后两种最容易。
  2) 官方提供皮肤供下载,用户可以使用下载的皮肤;
    用户可选择下载自己喜欢的皮肤,有些玩家会破解皮肤的定制方法,自己做皮肤使用,或者传到网上给大家用。
  3) 官方提供皮肤制作工具或方法,用户可自制皮肤。
    这种方式使用户有参与感,自由度较高。用户可根据自己的喜好定制软件的皮肤。有些软件官网提供皮肤定制的工具或者方法,我建议最好有可视化带向导的工具。用户只要自己找一些图片、修改文字的字体替换就可以了。用户可以上传自制的皮肤,提供其他用户下载,还可以赚得一些虚拟货币或者奖品什么的。这种一般都是打包为.zip格式的。扩展名可由各公司自定义,有制作工具的话直接导出来最方便。
首先我们要弄清楚换肤的定义,软件皮肤包括图标、字体、布局、交互风格等,换肤就是换掉皮肤包括的部分或所有资源。
  前面提到的三种皮肤,从软件实现上来看,它们的本质区别是皮肤是否内置到应用程序中。对于内置的实现比较简单,只要在开发应用的过程中设计几套皮肤供用户选择。这里用到的知识不超过Android基础,不详细讲解。
本节课程重点讲解如何实现皮肤与应用程序分离。
   皮肤一般含有多个文件,例如图片、配置等文件,分散的文件不利于传输和使用,最好打包。打包的格式一般选择zip格式。这里分两种情况,一种是apk,例如AdwLauncher,它的桌面皮肤格式是一个apk;另一种是自定义扩展名,例如墨迹天气皮肤扩展名是mja,搜狗输入法的皮肤扩展名是sga,它们的文件格式实际上都是zip。
  下面我们分别讲解。
  一.apk格式
   现在的问题变成了一个应用如何读取另一个apk中的资源。
   在android系统中,apk之间可以相互读取数据的条件是:有同样的签名,并且AndroidManifest.xml文件中配置的android:sharedUserId属性值相同,那么两个apk运行在同一个进程中,可以互相访问任意数据。
方法如下:

   1) 应用程序和皮肤程序的AndroidManifest.xml中配置
               例如: android:sharedUserId="com.kris.skin" ,值可以是做任意的,
   2) 文件与应用apk中对同一功能的皮肤文件名要一致
     例如:应用程序的背景图片路径:\SkinDemo\res\drawable-hdpi\bg.png
那么皮肤apk中的背景图片文件路径也应该是:
CustomSkin\res\drawable-hdpi\bg.png
   3)访问资源的方法

  1. Context context = createPackageContext("com.yuchen.customskin", Context.CONTEXT_IGNORE_SECURITY); 
复制代码
获取到org.yuchen.customskin对应的Context,通过返回的context对象就可以访问到org.yuchen.customskin中的任何资源。
   例如:应用apk要获得皮肤apk中的bg.png,
  1. Drawable drawable = context.getResources().getDrawable(R.drawable.bg);
复制代码
这样就得到了图片的引用,其他xml资源文件的获取方式也是类似的。
  二.自定义扩展名的zip格式的皮肤
    技术点在于如何去读取zip文件中的资源以及皮肤文件存放策略。
    方案:如果软件每次启动都去读取SD卡上的皮肤文件,速度会比较慢。较好的做法是提供一个皮肤设置的界面,用户选择了哪一个皮肤,就把那个皮肤文件解压缩到”/data/data/[package name]/skin”路径下,这样不需要跨存储器读取,速度较快,而且不需要每次都去zip压缩包中读取,不依赖SD卡中的文件,即使皮肤压缩包文件被删除了也没有关系。
实现方法:
    1. 在软件的帮助或者官网的帮助中提示用户将皮肤文件拷贝到SD卡指定路径下。
    2. 在软件中提供皮肤设置界面。可以在菜单或者在设置中。可参考墨迹、搜狗输入法、QQ等支持换肤的软件。
    3. 加载指定路径下的皮肤文件,读取其中的缩略图,在皮肤设置界面中显示,将用户选中的皮肤文件解压缩到”/data/data/[package name]/skin”路径下。
    4. 软件中优先读取”/data/data/[package name]/skin/”路径下的资源。如果没有则使用apk中的资源。

下面是我做的实例的截图与source ,我只测试了一下通过apk 来换肤的功能 ,到少其它的方法就留给大家去实验吧,不过记得实验了也上传图来大家一起分享哟。


图来了:
换肤前的截图:
before.png 
换肤后的截图:
after.png 

工程源码来了,re_skin是主程序 ,re_skin1是皮质程序,也就是提供资源的:
 source.zip (402.01 KB, 下载次数: 1586) 


方式二、

12.png 

界面上有说明,得先导入 皮肤文件,再换肤哦。。。

下面是皮肤文件,也就是一个包括资源文件的zip包,在这里去解压 zip包用到了这个帖子中的方法:
《[Android实例] 利用antzip包来进行解压与压缩》
http://www.eoeandroid.com/thread-102534-1-1.html

在运行项目前,记得先要下面的skin包上传到自己的sdcard目录下哦。当然这个名字啊,路径啊,你也可以自己在代码里面去改,甚至于zip包里面的资源也可以自己的修改,这就留给大家去发挥了。为了读取的快速及安全性,也可以把解压的目录放到程序有私有目录下面去哈,在这里为了方便就没去做这一步了,皮肤包来了:
 skin.zip (44.29 KB, 下载次数: 856) 

下面是代码来啰 !!
 Re_Skin2.zip (2.29 MB, 下载次数: 1884) 



方式三、

通过Style来完成

作者:kris更新于 04月07日访问(3014评论(66

changetheme.png
在long long ago ,写过两篇文章来实现换肤,在论坛里面不敢说人人皆知,但是人气还是到位了的.如果你还不知道,那赶快再去看看吧:
[Android实例] 【Kris专题】android 换肤 http://www.eoeandroid.com/thread-102060-1-1.html
[Android实例] 【kris专题】android 换肤(续) http://www.eoeandroid.com/thread-102536-1-1.html
另外一些在本文中会使用到的些知识:
【Kris专题】android Style 小结 http://www.eoeandroid.com/thread-99671-1-1.html
[Android实例] 【Kris专题】android:shape的使用 http://www.eoeandroid.com/thread-105450-1-1.html

 1 2 3 4 5 6 7 8 91011121314151617
然后今天我将给大家带来更神奇也更方便的一种方法来完成换肤.至于大家在项目中使用哪种方法就看大家的实际的项目需求了.这种换肤的主要思路是通过 Style来完成,如果大家对 Style的应用还不是很清楚,或者说是甚至没听说过,那你就危险了,至少足以证明你在Android界里面有多菜了.如果应用不是很熟悉,或者说他的原理不是很清楚的,自己可以多查阅一些资料,在这里就不作更仔细的介绍了.我们还是通过Demo 来一步步守成整个换肤的过程吧..1.当然是建议一个Android projects. 项目名什么的就随便你自己取了.我推荐大家在写自己的一些 demo的时候,指导编译 sdk可以设置到最高,别老是在2.x 徘徊了,有意思吗?2.项目建议好之后,就准备好各种我们图片资源文件吧(你可以ps一些背景图,也可以通过style中的shape来制作一些资源.或者说在color.xml中定义好一些颜色值,当然最方便的还是下载我的demo啦,里面啥都有了,呵呵 )3.在res/values目录下建议一个attrs.xml.里面用来定义一些style 的属性.如下:```java<?xml version="1.0" encoding="utf-8"?><resources>    <attr name="button" format="reference"/>    <attr name="background" format="reference"/>    <attr name="textColor" format="reference"/></resources>
 1 2 3 4 5 6 7 8 91011121314151617181920212223
    代码解释:        在上面的代码中,我们定义了三个属性(button,backgroud,textColor),这三个属性呢会在Style中用到,并且指出它的格式是引用形的.        比如说 button,它的值到时候我们会在style里面去设置,并且指向具体的某个资源文件.    4.然后到我们的res/values/style.xml了.(非常关键哦)    ```java    <resources xmlns:android="http://schemas.android.com/apk/res/android">        <style name="AppTheme_Default" parent="@android:style/Theme.Holo.Light.DarkActionBar">            <item name="button">@drawable/btn_grey</item>            <item name="background">@drawable/backgroud2</item>            <item name="textColor">@color/red</item>        </style>        <style name="AppTheme_Another" parent="AppTheme_Default">            <item name="button">@drawable/btn_blue</item>            <item name="background">@drawable/backgroud1</item>            <item name="android:actionBarStyle">@style/ActionBarStyle</item>        </style>        <style name="ActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">            <item name="android:background">#33b5e5</item>        </style>    </resources>
 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839
代码解释:    在这里我们定义了三个style (AppTheme_Default,AppTheme_Another,ActionBarStyle),其中AppTheme_Default,AppTheme_Another表示我们的两套主题.ActionBarStyle为我们actionBar的样式.    AppTheme_Default为默认的主题,它是继承至@android:style/Theme.Holo.Light.DarkActionBar.当然你也可以继承Android中任意的已经有的主题 或者是style , 你也可以选择不继承任何已经有的样式 .    AppTheme_Another为我们第二套主题 ,它是继承至AppTheme_Default的.在这里我们可以覆写部分AppTheme_Default里面的值,也可以覆写全部AppTheme_Default里面的值,这个看你具体的主题,也可以扩展其它一些新的值.    比如说在AppTheme_Another中,没有覆写textColor的值 ,也就是在这两种主题中,我的文字的颜色值都是使用AppTheme_Default主题 中的值,都为红色.但是又新增了一个android:actionBarStyle的样式来改变actionBar 的样式.5.接下来呢,我们再实现一个基础类,BaseActivity来代替所有的activity完成主题的切换(当然要求程序里面所有的activity 都得继承至 BaseActivity).```javapublic class BaseActivity extends Activity {    public int mTheme = R.style.AppTheme_Default;    @Override    protected void onCreate(Bundle savedInstanceState) {        if (savedInstanceState == null) {            mTheme = PreferenceHelper.getTheme(this);        } else {            mTheme = savedInstanceState.getInt("theme");        }        setTheme(mTheme);        super.onCreate(savedInstanceState);    }    @Override    protected void onResume() {        super.onResume();        if (mTheme != PreferenceHelper.getTheme(this)) {            reload();        }    }    protected void reload() {        Intent intent = getIntent();        overridePendingTransition(0, 0);        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);        finish();        overridePendingTransition(0, 0);        startActivity(intent);    }}
 1 2 3 4 5 6 7 8 91011
    代码解释:        onCreate中,我们从preference中去获取到主题,并且设置给 activity.        在onresume中再去检查主题 是否已经改变? 如果已经改变了,就重新加载activity ,否则没有动作.        reload就是finish当前 activity ,再启动当前activity啦.    6.万事俱备了,现在的问题是我们在atrrs中定义的button , background怎么使用呢?        a).java代码:```java            int[] attrs = new int[]{R.attr.button};            TypedArray typedArray = context.obtainStyledAttributes(attrs);
 1 2 3 4 5 6 7 8 91011121314151617181920212223242526
    具体的使用大家自行去测试了    b).直接在layout文件里面使用.比如我们 demo中的两个布局文件 .在这里我们例出一个来讲解.    second.xml    ```java    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="?attr/background" >        <TextView android:id="@+id/textview"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textColor="?attr/textColor"            android:layout_alignParentTop="true"            android:layout_centerHorizontal="true"            android:text="@string/msg_second" />        <Button            android:id="@+id/button"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:background="?attr/button"            android:text="@string/btn_text" />    </RelativeLayout>
 1 2 3 4 5 6 7 8 91011
        代码解释:            android:background="?attr/background"在这里使用了我们在attrs.xml中的background属性.            android:textColor="?attr/textColor" 使用了我们在attrs.xml中定义的textColor            android:background="?attr/button" 在这里使用了我们在attrs.xml中定义的button属性        我们再来走一个这个调用的流程.        在生成布局文件中RelativeLayout的时候,系统找到attrs.xml中定义的backround,然后再去当前设置的theme(我们假设是AppTheme_Default)中找到background指向的资源@drawable/backgroud2然后加载到内存赋值给RelativeLayout的android:background.如果当前主题 是AppTheme_Another,就会导入@drawable/backgroud1给RelativeLayout的android:background        好的.基本就讲到这里了.大家可以多看看  demo .多自己摸过下.        具体的  Demo下载地址: [http://www.eoeandroid.com/thread-264902-1-1.html](http://www.eoeandroid.com/thread-264902-1-1.html)或者我的博客: [http://www.krislq.com/2013/04/android_class_change_skin/](http://www.krislq.com/2013/04/android_class_change_skin/)

声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息

原文作者: kris

原文地址: http://my.eoe.cn/kris/archive/2245.html



原创粉丝点击