編輯:關於Android編程
近日春暖花開,又是一個金三銀四的季節,瞅瞅外面的風景,一聲長歎,還是埋頭繼續修技養神。近日在android主題上遇到了一個很糾結的問題,怎麼才能保證android更滑多種皮膚。經歷了三次實驗,各有不同,首先本文先講解一下依靠插件的方式更換主題:
簡介:把創建一個工程,把資源文件放入,然後打包成apk,放在主程序的Assets中,然後切換皮膚的時候,安裝該app,再根據皮膚apk的包名獲取“Resource”對象中得資源對象。
優點:本身皮膚就是一個apk,apk可以隨時下載,隨時安裝,可以控制版本動態的更新,靈活方便,因為安裝在手機的內存中,不收內存卡下載的影響。同時可以獨立於主程序,所以能減少主程序的體積大小。
缺點:第一次使用,需要用戶安裝;如果用戶下載了無法使用。
下面,我們來介紹相關的技術點:
1.怎麼獲取皮膚的Resource?
這個時候,就是用我們的PackageManger了。代碼:
PackageManager packageManager = getPackageManager(); try { PackageInfo packageInfo = packageManager.getPackageInfo(com.springsky.face1, PackageManager.GET_ACTIVITIES); resources = packageManager.getResourcesForApplication(packageInfo.applicationInfo); resource = new ReflectResource(resources, packageInfo.packageName); } catch (NameNotFoundException e) { Toast.makeText(this, 皮膚未安裝,請安裝皮膚, Toast.LENGTH_LONG).show(); e.printStackTrace(); }
上面的方式,首先使用getPackageManager()獲取到包管理者,然後使用包名獲取到Packageinfo對象,Packageinfo對象中,會保證程序的icon,版本等這種權限,目前大部分程序管理工具很神奇,就是依靠PackageManager完成的。從包PackageInfo對象中,我們可以得到Resource對象,其實,這個時候,我們已經成功一半了,因為得到這個,基本上皮膚的資源,我們是拿到了。接下來進入第二步。
2.怎麼獲取每個圖片資源的ID?
在我們得到的Resource對象中,有一個方法:res.getIdentifier(name,defType,defPackage) 這個方法 ,相當的重要,他返回的int,其實從英文字面意思,可以理解為 獲取唯一的辨識。也就是我們的ID,那麼下面的三個參數的意思分別為:
name:ID的名稱
defType:類型 ()
defPackage:包名稱
其實,也就是說,我們只要根據 我們的ID的名稱+類型+包名稱,就可以獲取到該圖片。
其實重點在defType這個參數,其實不難,這邊的取值也是固定的,比如:圖片=”drawable“,其他的什麼的,仔細閱讀介紹即可。
3.怎麼獲取資源對象?
其實,這個問題,你查閱Resource對象的方法是,會發現一個方法:getDrawable(id); 這個方法,真的不難理解,所以基本上就ok了吧。
下面我就簡單的提供一個工具類。
package com.springsky.facedemo; import java.io.IOException; import java.io.InputStream; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; import android.view.LayoutInflater; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; /*** * @author spring sky * 資源工具類 * Email:[email protected] * 創建時間:2014-4-25下午4:08:00 */ public class ReflectResource { private Resources res;// 獲取的資源apk裡面的res private String apkPackageName;// 資源apk裡面的包名 public ReflectResource(Resources res, String apkPackageName) { this.res = res; this.apkPackageName = apkPackageName; } /** * 獲取layout文件中的id號 * * @param layoutName * layout名 */ public int getResApkLayoutId(String layoutName) { return res.getIdentifier(layoutName, layout, apkPackageName); } /** * 獲取布局layout文件 * * @param context * 上下文 * @params layoutName * @return view */ public View getResApkLayoutView(Context context, String layoutName) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); return inflater.inflate(res.getLayout(getResApkLayoutId(layoutName)), null); } /** * 獲取控件view的id號 * * @param widgetName * 控件名 */ public int getResApkWidgetViewID(String widgetName) { return res.getIdentifier(widgetName, id, apkPackageName); } /** * 獲取布局文件中的控件 * * @params layout,資源apk中的布局(view) * @params widgetName 控件名稱 * @return widgetView */ public View getResApkWidgetView(View layout, String widgetName) { return layout.findViewById(getResApkWidgetViewID(widgetName)); } /** * 獲取drawable文件的id * * @param DrawableName * 圖片名字 */ public int getDrawableId(String imgName) { return res.getIdentifier(imgName, drawable, apkPackageName); } /** * 獲取圖片資源 * * @param imgName * @return drawable */ public Drawable getResApkDrawable(String imgName) { int id = getDrawableId(imgName); if(id > 0){ return res.getDrawable(id); } Log.i(getResApkDrawable, imgName+ 在皮膚插件中未找到); return null; } /** * 獲取string文件中的id號 * * @param stringName * 字符串在String文件中的名字 */ public int getResApkStringId(String stringName) { return res.getIdentifier(stringName, string, apkPackageName); } /** * 獲取String字符串 * * @param stringName * @return string */ public String getResApkString(String stringName) { return res.getString(getResApkStringId(stringName)); } /** * 獲取anim文件中的id號 * * @param animationName */ public int getResApkAnimId(String animationName) { return res.getIdentifier(animationName, anim, apkPackageName); } /** * 獲取anim文件 XmlPullParser * * @param animationName * @return XmlPullParser */ public XmlPullParser getResApkAnimXml(String animationName) { return res.getAnimation(getResApkAnimId(animationName)); } /** * 獲取動畫anim * * @params animationName * @param animation */ public Animation getResApkAnim(Context context, String animationName) { Animation animation = null; XmlPullParser parser = getResApkAnimXml(animationName); AttributeSet attrs = Xml.asAttributeSet(parser); try { animation = createAnimationFromXml(context, parser, null, attrs); } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return animation; } /** * 獲取anim動畫 */ private Animation createAnimationFromXml(Context c, XmlPullParser parser, AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException { Animation anim = null; int type; int depth = parser.getDepth(); while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } String name = parser.getName(); if (name.equals(set)) { anim = new AnimationSet(c, attrs); createAnimationFromXml(c, parser, (AnimationSet) anim, attrs); } else if (name.equals(alpha)) { anim = new AlphaAnimation(c, attrs); } else if (name.equals(scale)) { anim = new ScaleAnimation(c, attrs); } else if (name.equals(rotate)) { anim = new RotateAnimation(c, attrs); } else if (name.equals(translate)) { anim = new TranslateAnimation(c, attrs); } else { throw new RuntimeException(Unknown animation name: + parser.getName()); } if (parent != null) { parent.addAnimation(anim); } } return anim; } /** * 獲取 color文件中的id號 * * @param colorName */ public int getResApkColorId(String colorName) { return res.getIdentifier(colorName, color, apkPackageName); } /** * 獲取color 值 * * @param colorName * @return int */ public int getResApkColor(String colorName) { return res.getColor(getResApkColorId(colorName)); } /** * 獲取 dimens文件中的id號 * * @param dimenName */ public int getResApkDimensId(String dimenName) { return res.getIdentifier(dimenName, dimen, apkPackageName); } /** * 獲取dimens文件中值 * * @param dimenName * @return float */ public float getResApkDimens(String dimenName) { return res.getDimension(getResApkDimensId(dimenName)); } public InputStream getResApkRaw(String string) { return res.openRawResource(getResApkRawId(string)); } private int getResApkRawId(String string) { return res.getIdentifier(string, raw, apkPackageName); } }
以上工具類,基本上提供了 各種方法來獲取Resource的所有資源,所以,這下放心了把。
具體界面實現只有一行代碼:
findViewById(R.id.btn_bg).setBackgroundDrawable(resource.getResApkDrawable(more_item_bg));這樣就可以完成換膚功能了!
總結:總體來說,如果項目中能接受該方式安裝apk,我試極力推薦該apk,因為這樣皮膚可以做成插件,封層清楚,同時可以在多個項目中使用。如有疑問請聯系我。
Face1Resource 項目為皮膚工程
FaceDemo 項目為測試皮膚主程序,使用前請先安裝皮膚。
最近在學Android 學的不好 然後看到了用.9.png寫對話框的哪裡,但是書上寫的太簡單 感覺做出來和書上的不一樣 然後就去各種百度 感覺網上關於這個東西的資料都是粘
做一個簡單的記錄。google搞了一大套 dip、sp、mdpi、hdpi、xhdpi之類的這些東西,簡單說來,就是為了讓我們輕松實現“與設備密度無關的視覺大
本文本著開源的精神介紹如何向一個Android系統中添加一個產品的整個過程,按照以下過程筆者有理由相信每個將要從事本行業的人都可以完成,其實添加一個產品並不難,難的是對其
最近研究了一下Contacts源碼,仿照上面自己寫了一個TabHostTest程序,現整理如下:main.xml布局文件:<?xml version=1.0