知識
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價值,我們在追求其視覺表現(xiàn)的同時,更側(cè)重于功能的便捷,營銷的便利,運營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序為后期升級提供便捷的支持!
輕松實現(xiàn)Android更換皮膚(主題)
發(fā)表時間:2020-10-19
發(fā)布人:葵宇科技
瀏覽次數(shù):95
今朝很多app都具有換膚功能,可以根據(jù)用戶本身的愛好定制本身的界面,比如新浪微博,網(wǎng)易消息等等。今天這里我就是要介紹一種機制實現(xiàn)app換膚。
我找了幾款app換膚的應(yīng)用,換膚根本都是改換了界面的Icon,背景圖片,配風(fēng)景等等,根本沒有碰到改換構(gòu)造的,其實結(jié)垢荷飼可以改換的,然則認為沒有須要。所以這篇文┞仿講解的換膚也是指換icon,背景圖片等資本。
經(jīng)由過程收集搜刮我發(fā)明網(wǎng)上上供給了大年夜概這么集中換膚機制:
1、直接將皮膚包放入apk中,這種籌劃實現(xiàn)異常簡單,然則不敷靈活,并且還將apk搞大年夜了。
2、將皮膚做成一個自力的apk文件,并和項目工程公用一個shareUsedId,并擁有雷同的簽名。這種籌劃較第一種方檀卷是靈活性比較大年夜,缺點就是須要用戶安裝,新浪微博今朝應(yīng)用的就是這種籌劃。
我今天要介紹的┞封種籌劃和第二種比較類似,然則我的資本包是不要安裝的,畢竟用戶一般愿意裝一些混亂無章的應(yīng)用。
在進修這篇文┞仿之前最好進修我的前一篇文┞仿《Android資本治理機制分析》,因為皮膚治理其實就是資本的治理。下面開端進修若何換膚吧
1、起首我們須要預(yù)備一個皮膚包,這個皮膚包瑯綾擎不會包含任何Activity,瑯綾擎只有資本文件,這里我為了簡單,僅僅參加一個color.xml(其實就相當于Android體系中的framework_res.apk)
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="main_btn_color">#E61ABD</color> <color name="main_background">#38F709</color> <color name="second_btn_color">#000000</color> <color name="second_background">#FFFFFF</color> </resources>
2、將該資本打包成apk文件,放入sd卡中(實際項目你可以大年夜我收集下載)
3、將須要換膚的Activity實現(xiàn)ISkinUpdate(這個可以本身隨便定義名稱)接口
public class MainActivity extends Activity implements ISkinUpdate,OnClickListener { private Button btn_main; private View main_view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.activity_main); SkinApplication.getInstance().mActivitys.add(this); btn_main=(Button)this.findViewById(R.id.btn_main); btn_main.setOnClickListener(this); main_view=this.findViewById(R.id.main_view); } @Override protected void onResume() { super.onResume(); if(SkinPackageManager.getInstance(this).mResources!=null) { updateTheme(); Log.d("yzy", "onResume-->updateTheme"); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { //Toast.makeText(this, "change skin", 1000).show(); File dir=new File(Environment.getExternalStorageDirectory(),"plugins"); File skin=new File(dir,"SkinPlugin.apk"); if(skin.exists()) { SkinPackageManager.getInstance(MainActivity.this).loadSkinAsync(skin.getAbsolutePath(), new loadSkinCallBack() { @Override public void startloadSkin() { Log.d("yzy", "startloadSkin"); } @Override public void loadSkinSuccess() { Log.d("yzy", "loadSkinSuccess"); MainActivity.this.sendBroadcast(new Intent(SkinBroadCastReceiver.SKIN_ACTION)); } @Override public void loadSkinFail() { Log.d("yzy", "loadSkinFail"); } }); } return true; } return super.onOptionsItemSelected(item); } @Override public void updateTheme() { // TODO Auto-generated method stub if(btn_main!=null) { try { Resources mResource=SkinPackageManager.getInstance(this).mResources; Log.d("yzy", "start and mResource is null-->"+(mResource==null)); int id1=mResource.getIdentifier("main_btn_color", "color", "com.skin.plugin"); btn_main.setBackgroundColor(mResource.getColor(id1)); int id2=mResource.getIdentifier("main_background", "color","com.skin.plugin"); main_view.setBackgroundColor(mResource.getColor(id2)); //img_skin.setImageDrawable(mResource.getDrawable(mResource.getIdentifier("skin", "drawable","com.skin.plugin"))); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override protected void onDestroy() { // TODO Auto-generated method stub SkinApplication.getInstance().mActivitys.remove(this); super.onDestroy(); } @Override public void onClick(View v) { // TODO Auto-generated method stub if(v.getId()==R.id.btn_main) { Intent intent=new Intent(this,SecondActivity.class); this.startActivity(intent); } } }
這段代率攀瑯綾擎重要看onOptionsItemSelected,這個辦法瑯綾擎,經(jīng)由過程資本apk路徑,拿到該資本apk對應(yīng)Resources對象。我們直接看看SkinPacakgeManager瑯綾擎做了什么吧
/** * 解析皮膚資本包 * com.skin.demo.SkinPackageManager * @author yuanzeyao <br/> * create at 2015年1月3日 下晝3:24:16 */ public class SkinPackageManager { private static SkinPackageManager mInstance; private Context mContext; /** * 當緇な源包名 */ public String mPackageName; /** * 皮膚資本 */ public Resources mResources; private SkinPackageManager(Context mContext) { this.mContext=mContext; } public static SkinPackageManager getInstance(Context mContext) { if(mInstance==null) { mInstance=new SkinPackageManager(mContext); } return mInstance; } /** * 異步加載皮膚資本 * @param dexPath * 須要加載的皮膚資本 * @param callback * 回調(diào)接口 */ public void loadSkinAsync(String dexPath,final loadSkinCallBack callback) { new AsyncTask<String,Void,Resources>() { protected void onPreExecute() { if(callback!=null) { callback.startloadSkin(); } }; @Override protected Resources doInBackground(String... params) { try { if(params.length==1) { String dexPath_tmp=params[0]; PackageManager mPm=mContext.getPackageManager(); PackageInfo mInfo=mPm.getPackageArchiveInfo(dexPath_tmp,PackageManager.GET_ACTIVITIES); mPackageName=mInfo.packageName; AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class); addAssetPath.invoke(assetManager, dexPath_tmp); Resources superRes = mContext.getResources(); Resources skinResource=new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); SkinConfig.getInstance(mContext).setSkinResourcePath(dexPath_tmp); return skinResource; } return null; } catch (Exception e) { return null; } }; protected void onPostExecute(Resources result) { mResources=result; if(callback!=null) { if(mResources!=null) { callback.loadSkinSuccess(); }else { callback.loadSkinFail(); } } }; }.execute(dexPath); } /** * 加載資本的回調(diào)接口 * com.skin.demo.loadSkinCallBack * @author yuanzeyao <br/> * create at 2015年1月4日 下晝1:45:48 */ public static interface loadSkinCallBack { public void startloadSkin(); public void loadSkinSuccess(); public void loadSkinFail(); } }調(diào)用loadSkinAsync后,如不雅成功,就會發(fā)送一個換膚廣播,并將當前皮膚apk的路徑保存到sp中,便于下次啟動app是直接加載該皮膚資本。
接收換膚廣播是在SkinApplication中注冊的,當接收到此廣播后,隨即調(diào)用所有已經(jīng)啟動,并且須要換膚的Activity的updateTheme辦法,大年夜而實現(xiàn)換膚。
public class SkinApplication extends Application { private static SkinApplication mInstance=null; public ArrayList<ISkinUpdate> mActivitys=new ArrayList<ISkinUpdate>(); @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); mInstance=this; String skinPath=SkinConfig.getInstance(this).getSkinResourcePath(); if(!TextUtils.isEmpty(skinPath)) { //如不雅已經(jīng)換皮膚,那么第二次進來時,須要加載該皮膚 SkinPackageManager.getInstance(this).loadSkinAsync(skinPath, null); } SkinBroadCastReceiver.registerBroadCastReceiver(this); } public static SkinApplication getInstance() { return mInstance; } @Override public void onTerminate() { // TODO Auto-generated method stub SkinBroadCastReceiver.unregisterBroadCastReceiver(this); super.onTerminate(); } public void changeSkin() { for(ISkinUpdate skin:mActivitys) { skin.updateTheme(); } } }
因為這里換膚僅僅是改換icon,配風(fēng)景之類的,所以比較簡單,如不雅要改換構(gòu)造文件,那就稍微要復(fù)雜一些,這里就不再介紹了,有興趣的可以本身去研究..
相關(guān)案例查看更多
相關(guān)閱讀
- 網(wǎng)站建設(shè)招商
- 網(wǎng)站建設(shè)專家
- 云南建設(shè)廳官方網(wǎng)站
- 小程序被騙
- 網(wǎng)站建設(shè)服務(wù)
- 云南旅游網(wǎng)站建設(shè)
- 網(wǎng)頁制作
- python開發(fā)小程序
- 云南小程序開發(fā)課程
- 模版消息
- 公眾號模板消息
- 搜索引擎優(yōu)化
- 小程序定制
- 軟件定制
- 汽車回收系統(tǒng)
- 云南小程序開發(fā)報價
- 云南網(wǎng)站建設(shè) 網(wǎng)絡(luò)服務(wù)
- 云南小程序開發(fā)
- 小程序分銷商城
- 昆明軟件定制公司
- 網(wǎng)站開發(fā)
- 網(wǎng)站建設(shè)電話
- 快排推廣
- 網(wǎng)站建設(shè)公司哪家好
- 小程序技術(shù)
- 排名
- 開通微信小程序被騙
- 小程序生成海報
- 網(wǎng)站建設(shè)方案 doc
- 制作一個小程序