标签:
在这里谈一下墨迹天气的换肤实现方式,不过首先声明我只是通过反编译以及参考了一些网上其他资料的方式推测出的换肤原理, 在这里只供参考. 若大家有更好的方式, 欢迎交流.
墨迹天气下载的皮肤就是一个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:
- <?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;
-
- 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包的工具类
- 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;
- }
- }
Android 打造自己的个性化应用(四):仿墨迹天气实现-->自定义扩展名的zip格式的皮肤
标签:
原文地址:http://www.cnblogs.com/dongweiq/p/4249931.html