在這里談一下墨跡天氣的換膚實現方式,不過首先聲明我只是通過反編譯以及參考了一些網上其他資料的方式推測出的換膚原理, 在這里只供參考. 若大家有更好的方式, 歡迎交流.
?
?
墨跡天氣下載的皮膚就是一個zip格式的壓縮包,在應用的時候把皮膚資源釋放到墨跡天氣應用的目錄下,更換皮膚時新的皮膚資源會替換掉老的皮膚資源每次加載的時候就是從手機硬盤上讀取圖片,這些圖片資源的命名和程序中的資源的命名保持一致,一旦找不到這些資源,可以選擇到系統默認中查找。這種實現是直接讀取了外部資源文件,在程序運行時通過代碼顯示的替換界面的背景資源。這種方式的優點是:皮膚資源的格式定義很隨意可以是zip也可以是自定義的格式,只要程序中能夠解析到資源就行,缺點是效率上的問題.
?
這里需要注意的一點是,再這里對壓縮包的解壓,借助了第三方工具: ant. jar進行解壓和壓縮文件. 關于ant工具的使用,我在稍后的文章中會具體介紹.
?
主要技術點:
如何去讀取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中的資源。
?
效果圖:
?
具體代碼:
1. AndroidManifest.xml:
?
[java]?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>??<manifest?xmlns:android="http://schemas.android.com/apk/res/android"??????package="com.tony.skin"?android:versionCode="1"?android:versionName="1.0">??????<uses-sdk?android:minSdkVersion="7"?/>??????<uses-permission?android:name="android.permission.WRITE_EXTERNAL_STORAGE"?/>??????<application?android:icon="@drawable/icon"?android:label="@string/app_name">??????????<activity?android:name=".Re_Skin2Activity"????????????????????android:label="@string/app_name">??????????????<intent-filter>??????????????????<action?android:name="android.intent.action.MAIN"?/>??????????????????<category?android:name="android.intent.category.LAUNCHER"?/>??????????????</intent-filter>??????????</activity>????????</application>??</manifest>??
2.布局文件main.xml
?
?
[java]?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>??<LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??????android:orientation="vertical"??????android:layout_width="fill_parent"??????android:layout_height="fill_parent"??????android:background="#d2d2d2"??????android:id="@+id/layout">??????<Button?android:text="導入皮膚"?android:id="@+id/button2"?android:layout_width="wrap_content"?android:layout_height="wrap_content"></Button>??????<Button?android:text="換膚"?android:id="@+id/button1"?android:layout_width="wrap_content"?android:layout_height="wrap_content"></Button>??????<TextView?android:id="@+id/textView1"?android:layout_width="wrap_content"?android:layout_height="wrap_content"???????????android:text="請先點擊“導入皮膚”,會將/sdcard/skin.zip導入到/sdcard/Skin_kris目錄下,然后點擊‘換膚’會將sdcard里面的素材用作皮膚"???????????android:textColor="#000"></TextView>??</LinearLayout>??
3. Re_Skin2Activity:
?
?
[java]?view plaincopy
package?com.tony.skin;????import?android.app.Activity;??import?android.graphics.Bitmap;??import?android.graphics.BitmapFactory;??import?android.graphics.drawable.BitmapDrawable;??import?android.os.Bundle;??import?android.view.View;??import?android.view.View.OnClickListener;??import?android.widget.Button;??import?android.widget.LinearLayout;??import?android.widget.Toast;????import?com.tony.skin.utils.ZipUtil;????public?class?Re_Skin2Activity?extends?Activity?implements?OnClickListener{??????private?Button??btnSet;??????private?Button??btnImport;??????private?LinearLayout?layout;??????????@Override??????public?void?onCreate(Bundle?savedInstanceState)?{??????????super.onCreate(savedInstanceState);??????????setContentView(R.layout.main);??????????btnSet?=?(Button)findViewById(R.id.button1);??????????btnSet.setOnClickListener(this);????????????btnImport?=?(Button)findViewById(R.id.button2);??????????btnImport.setOnClickListener(this);??????????layout?=?(LinearLayout)findViewById(R.id.layout);??????}??????@Override??????public?void?onClick(View?v)?{??????????switch?(v.getId())?{??????????case?R.id.button1:??????????????Bitmap?bitmap=?BitmapFactory.decodeFile("/sdcard/tony/skin/skin.png");?????????????????????????????BitmapDrawable?bd=new?BitmapDrawable(bitmap);??????????????btnSet.setBackgroundDrawable(bd);????????????????????????????layout.setBackgroundDrawable(new?BitmapDrawable(BitmapFactory.decodeFile("/sdcard/Skin_kris/skin/bg/bg.png")));????????????????????????????break;??????????case?R.id.button2:??????????????ZipUtil?zipp?=?new?ZipUtil(2049);??????????????System.out.println("begin?do?zip");??????????????zipp.unZip("/sdcard/skin.zip","/sdcard/Skin_kris");??????????????Toast.makeText(this,?"導入成功",?Toast.LENGTH_SHORT).show();??????????????break;??????????default:??????????????break;??????????}??????}??}??
4. ZipUtil 解壓縮處理ZIP包的工具類
?
?
[java]?view plaincopy
package?com.tony.skin.utils;????import?java.io.BufferedOutputStream;??import?java.io.File;??import?java.io.FileInputStream;??import?java.io.FileOutputStream;??import?java.io.IOException;??import?java.io.InputStream;??import?java.util.Enumeration;??import?java.util.zip.Deflater;????import?org.apache.tools.zip.ZipEntry;??import?org.apache.tools.zip.ZipFile;??import?org.apache.tools.zip.ZipOutputStream;????public?class?ZipUtil?{??????private?ZipFile?????????zipFile;???????private?ZipOutputStream?zipOut;?????????private??int????????????bufSize;????????private?byte[]??????????buf;???????private?int?????????????readedBytes;???????public?ZipUtil(){???????????this(512);???????}?????????public?ZipUtil(int?bufSize){???????????this.bufSize?=?bufSize;???????????this.buf?=?new?byte[this.bufSize];???????}??????????????????public?void?doZip(String?srcFile,?String?destFile)?{????????File?zipDir;??????????String?dirName;????????????zipDir?=?new?File(srcFile);??????????dirName?=?zipDir.getName();??????????try?{??????????????this.zipOut?=?new?ZipOutputStream(new?BufferedOutputStream(??????????????????????new?FileOutputStream(destFile)));??????????????????????????zipOut.setComment("comment");??????????????????????????zipOut.setEncoding("GBK");??????????????????????????zipOut.setMethod(ZipOutputStream.DEFLATED);?????????????????????????????zipOut.setLevel(Deflater.BEST_COMPRESSION);?????????????????????????????handleDir(zipDir,?this.zipOut,dirName);??????????????this.zipOut.close();??????????}?catch?(IOException?ioe)?{??????????????ioe.printStackTrace();??????????}??????}????????????private?void?handleDir(File?dir,?ZipOutputStream?zipOut,String?dirName)?throws?IOException?{??????????System.out.println("遍歷目錄:"+dir.getName());??????????FileInputStream?fileIn;??????????File[]?files;????????????files?=?dir.listFiles();????????????if?(files.length?==?0)?{????????????????????????System.out.println("壓縮的 Name:"+dirName);??????????????this.zipOut.putNextEntry(new?ZipEntry(dirName));??????????????this.zipOut.closeEntry();??????????}?else?{????????????for?(File?fileName?:?files)?{????????????????????????????????????if?(fileName.isDirectory())?{??????????????????????handleDir(fileName,?this.zipOut,dirName+File.separator+fileName.getName()+File.separator);??????????????????}?else?{??????????????????????System.out.println("壓縮的 Name:"+dirName?+?File.separator+fileName.getName());??????????????????????fileIn?=?new?FileInputStream(fileName);??????????????????????this.zipOut.putNextEntry(new?ZipEntry(dirName?+?File.separator+fileName.getName()));????????????????????????while?((this.readedBytes?=?fileIn.read(this.buf))?>?0)?{??????????????????????????this.zipOut.write(this.buf,?0,?this.readedBytes);??????????????????????}????????????????????????this.zipOut.closeEntry();??????????????????}??????????????}??????????}??????}????????????public?void?unZip(String?unZipfile,?String?destFile)?{????????FileOutputStream?fileOut;??????????File?file;??????????InputStream?inputStream;????????????try?{??????????????this.zipFile?=?new?ZipFile(unZipfile);????????????????for?(Enumeration?entries?=?this.zipFile.getEntries();?entries??????????????????????.hasMoreElements();)?{??????????????????ZipEntry?entry?=?(ZipEntry)?entries.nextElement();??????????????????file?=?new?File(destFile+File.separator+entry.getName());????????????????????if?(entry.isDirectory())?{??????????????????????file.mkdirs();??????????????????}?else?{??????????????????????????????????????????File?parent?=?file.getParentFile();??????????????????????if?(!parent.exists())?{??????????????????????????parent.mkdirs();??????????????????????}????????????????????????inputStream?=?zipFile.getInputStream(entry);????????????????????????fileOut?=?new?FileOutputStream(file);??????????????????????while?((this.readedBytes?=?inputStream.read(this.buf))?>?0)?{??????????????????????????fileOut.write(this.buf,?0,?this.readedBytes);??????????????????????}??????????????????????fileOut.close();????????????????????????inputStream.close();??????????????????}??????????????}??????????????this.zipFile.close();??????????}?catch?(IOException?ioe)?{??????????????ioe.printStackTrace();??????????}??????}????????????public?void?setBufSize(int?bufSize)?{??????????this.bufSize?=?bufSize;??????}??}?
轉載于:https://www.cnblogs.com/dongweiq/p/4249931.html
總結
以上是生活随笔為你收集整理的Android 打造自己的个性化应用(四):仿墨迹天气实现--自定义扩展名的zip格式的皮肤...的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。