android換膚

方式一、


國內有很多的軟件都支持皮膚定製,這也是與國外軟件重大不同之一,國外用戶注重社交、郵件等功能,國內用戶則重視音樂、小說、皮膚等功能,本節課程就來講解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
 9
10
11
12
13
14
15
16
17
然後今天我將給大家帶來更神奇也更方便的一種方法來完成換膚.至於大家在項目中使用哪種方法就看大家的實際的項目需求了.

這種換膚的主要思路是通過 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
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    代碼解釋:
        在上面的代碼中,我們定義了三個屬性(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
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
代碼解釋:
    在這裏我們定義了三個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).
```java
public 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
 9
10
11
    代碼解釋:
        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
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    具體的使用大家自行去測試了

    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
 9
10
11
        代碼解釋:
            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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章