亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

仿墨跡天氣在Android App中實現自定義zip皮膚更換

2020-01-02 07:03:37
字體:
來源:轉載
供稿:網友

在這里談一下墨跡天氣的換膚實現方式,不過首先聲明我只是通過反編譯以及參考了一些網上其他資料的方式推測出的換膚原理, 在這里只供參考. 若大家有更好的方式, 歡迎交流.
墨跡天氣下載的皮膚就是一個zip格式的壓縮包,在應用的時候把皮膚資源釋放到墨跡天氣應用的目錄下,更換皮膚時新的皮膚資源會替換掉老的皮膚資源每次加載的時候就是從手機硬盤上讀取圖片,這些圖片資源的命名和程序中的資源的命名保持一致,一旦找不到這些資源,可以選擇到系統默認中查找。這種實現是直接讀取了外部資源文件,在程序運行時通過代碼顯示的替換界面的背景資源。這種方式的優點是:皮膚資源的格式定義很隨意可以是zip也可以是自定義的格式,只要程序中能夠解析到資源就行,缺點是效率上的問題.

這里需要注意的一點是,再這里對壓縮包的解壓,借助了第三方工具: ant. jar進行解壓和壓縮文件. 關于ant工具的使用,我在稍后的文章中會具體介紹.

主要技術點:
如何去讀取zip文件中的資源以及皮膚文件存放方式

實現方案:如果軟件每次啟動都去讀取SD卡上的皮膚文件,速度會比較慢。較好的做法是提供一個皮膚設置的界面,用戶選擇了哪一個皮膚,就把那個皮膚文件解壓縮到”/data/data/[package name]/skin”路徑下(讀取的快速及安全性),這樣不需要跨存儲器讀取,速度較快,而且不需要每次都去zip壓縮包中讀取,不依賴SD卡中的文件,即使皮膚壓縮包文件被刪除了也沒有關系。
實現方法:
1. 在軟件的幫助或者官網的幫助中提示用戶將皮膚文件拷貝到SD卡指定路徑下。
2. 在軟件中提供皮膚設置界面??梢栽诓藛位蛘咴谠O置中。可參考墨跡、搜狗輸入法、QQ等支持換膚的軟件。
3. 加載指定路徑下的皮膚文件,讀取其中的縮略圖,在皮膚設置界面中顯示,將用戶選中的皮膚文件解壓縮到”/data/data/[package name]/skin”路徑下。
4. 軟件中優先讀取”/data/data/[package name]/skin/”路徑下的資源。如果沒有則使用apk中的資源。

效果圖:

2016226153459744.jpg (375×517)

具體代碼:
1. AndroidManifest.xml:

<?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

<?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:

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;  /**  *  * @author Tony  *  */ public class Re_Skin2Activity extends Activity implements OnClickListener{   private Button btnSet;   private Button btnImport;   private LinearLayout layout;   /** Called when the activity is first created. */   @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包的工具類

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;  /**  * Zip包壓縮,解壓處理工具類  * @author a  *  */ public class ZipUtil {   private ZipFile     zipFile;    private ZipOutputStream zipOut;   //壓縮Zip    private int      bufSize;  //size of bytes    private byte[]     buf;    private int       readedBytes;    public ZipUtil(){      this(512);    }     public ZipUtil(int bufSize){      this.bufSize = bufSize;      this.buf = new byte[this.bufSize];    }        /**    *    * @param srcFile 需要 壓縮的目錄或者文件    * @param destFile 壓縮文件的路徑    */   public void doZip(String srcFile, String destFile) {// zipDirectoryPath:需要壓縮的文件夾名     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();     }   }    /**    * 由doZip調用,遞歸完成目錄文件讀取    * @param dir    * @param zipOut    * @param dirName 這個主要是用來記錄壓縮文件的一個目錄層次結構的    * @throws IOException    */   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) {// 如果目錄為空,則單獨創建之.       // ZipEntry的isDirectory()方法中,目錄以"/"結尾.       System.out.println("壓縮的 Name:"+dirName);       this.zipOut.putNextEntry(new ZipEntry(dirName));       this.zipOut.closeEntry();     } else {// 如果目錄不為空,則分別處理目錄和文件.       for (File fileName : files) {         // System.out.println(fileName);          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();         }       }     }   }    /**    * 解壓指定zip文件    * @param unZipfile 壓縮文件的路徑    * @param destFile   解壓到的目錄     */   public void unZip(String unZipfile, String destFile) {// unZipfileName需要解壓的zip文件名     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;   } } 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人h猎奇视频网站| 中文字幕久热精品在线视频| www.国产精品一二区| 亚洲风情亚aⅴ在线发布| 亚洲全黄一级网站| 久久免费精品日本久久中文字幕| 国产亚洲一区二区在线| 午夜精品在线视频| 51精品国产黑色丝袜高跟鞋| 在线电影欧美日韩一区二区私密| 国产精品第一视频| 8x海外华人永久免费日韩内陆视频| 国产大片精品免费永久看nba| 色婷婷av一区二区三区在线观看| 中日韩午夜理伦电影免费| 久久亚洲精品国产亚洲老地址| 国产日韩精品综合网站| 精品毛片三在线观看| 亚洲理论片在线观看| 久久久久久中文字幕| 欧美成人黄色小视频| 精品国产自在精品国产浪潮| 日本久久久久久久久久久| 亚洲国产精品一区二区久| 国产精品入口免费视| 亚洲精品一区久久久久久| 精品国产一区二区三区久久狼5月| 亚洲人成电影网站| 国产精品十八以下禁看| 久久国产精品影片| 日韩精品视频在线观看网址| 深夜精品寂寞黄网站在线观看| 日韩**中文字幕毛片| 91亚洲精品久久久久久久久久久久| 亚洲欧美综合另类中字| 国产第一区电影| 青青草国产精品一区二区| 国产日本欧美一区二区三区| 欧美一级黄色网| 亚洲人成啪啪网站| 亚洲欧美成人一区二区在线电影| 亚洲情综合五月天| 亚洲精品有码在线| 久久中文字幕在线| 懂色aⅴ精品一区二区三区蜜月| 秋霞av国产精品一区| 国产97色在线|日韩| 51久久精品夜色国产麻豆| 日韩视频欧美视频| 亚洲欧美日韩爽爽影院| 亚洲视频在线免费看| 亚洲精品久久久久久下一站| 国产精品高潮呻吟视频| 九九热视频这里只有精品| 97精品欧美一区二区三区| 亚洲欧美成人精品| 国产欧美一区二区三区久久人妖| 欧美视频在线观看免费网址| 亚洲日本欧美日韩高观看| 欧美成人精品影院| 久久久免费观看| 亚洲女人天堂av| 亚洲午夜色婷婷在线| 欧美人与性动交a欧美精品| 亚洲国产精品小视频| 中文字幕国产日韩| 亚洲欧美另类中文字幕| 91av在线免费观看视频| 黑丝美女久久久| 日本韩国欧美精品大片卡二| 久久999免费视频| 日本精品久久久久久久| 亚洲午夜精品久久久久久久久久久久| 超碰97人人做人人爱少妇| 亚洲成人精品在线| 亚洲另类图片色| 久久久久999| 亚洲欧美国产高清va在线播| 亚洲欧美综合另类中字| 国产精品久久久| 亚洲成色777777在线观看影院| 日韩麻豆第一页| 亚洲性线免费观看视频成熟| 亚洲欧美日韩在线一区| 97免费视频在线| 91豆花精品一区| 国产精品video| 久久精品国产精品亚洲| 日韩精品高清在线观看| 国产高清在线不卡| 亚洲中国色老太| 91精品视频免费观看| 久久久精品一区二区| 成年无码av片在线| 日韩免费电影在线观看| 91免费在线视频| 91精品国产乱码久久久久久久久| 日韩av在线播放资源| 91精品视频免费| 亚洲天堂男人天堂女人天堂| 在线精品国产欧美| 91精品国产高清久久久久久91| 在线中文字幕日韩| 亚洲欧美999| 成人精品网站在线观看| 久久精品国产精品亚洲| 上原亚衣av一区二区三区| 国产精品久久久久久久久久ktv| 国产日韩中文字幕| 色偷偷噜噜噜亚洲男人的天堂| 日韩电影中文 亚洲精品乱码| 亚洲国产日韩欧美在线图片| 国产精品视频播放| 精品香蕉在线观看视频一| 不卡av电影院| 欧美性猛交99久久久久99按摩| 欧美一级成年大片在线观看| 日日狠狠久久偷偷四色综合免费| 国产精品www网站| 国产精品视频1区| 亚洲一区二区中文| 国产一区视频在线播放| 黄色一区二区在线观看| 成人黄色免费看| 精品中文字幕在线| 精品福利一区二区| 国产成人精品一区二区在线| 亚洲第一网中文字幕| 亚洲天堂男人天堂| 亚洲天堂网站在线观看视频| 亚洲美女免费精品视频在线观看| 欧美丰满片xxx777| 日韩av综合中文字幕| 精品久久久久久久大神国产| 亚洲精品久久视频| 91精品国产综合久久香蕉| 中文国产亚洲喷潮| 51色欧美片视频在线观看| 久久视频这里只有精品| 日韩第一页在线| 久久精品最新地址| 深夜福利亚洲导航| 国产69久久精品成人| 久久久久久久国产| 国产精品高清在线| 国产91在线播放九色快色| 91色精品视频在线| 欧美极品欧美精品欧美视频| 国语自产在线不卡| 欧美日本亚洲视频| 亚洲毛片在线观看| 亚洲四色影视在线观看| 国产福利精品av综合导导航| 91精品久久久久久久久久入口| 一区二区欧美亚洲| 国产网站欧美日韩免费精品在线观看| 在线播放精品一区二区三区| 91精品国产自产在线老师啪| 国内精品视频久久| 精品久久中文字幕久久av| 久久天天躁日日躁| 久久亚洲影音av资源网| 国产精品一区二区久久国产| 欧美日韩一二三四五区|