Android如何实现皮肤的定制与更换
本篇主要是一个demo,该切换主题的demo里面一共实现了两个功能,其一,搜索已经安装的皮肤,其二,应用安装的皮肤。
主项目包名为org.leepood.skindemo,主题项目的包名为org.leepood.skin.blue,org.leepood.skin.red,等等,只要前缀是org.leepood.skin.就行。
首先是查找已安装主题的代码:
01.package org.leepood.skindemo;??
02.?
03.import java.util.ArrayList;??
04.import java.util.List;??
05.?
06.import android.app.Activity;??
07.import android.app.ProgressDialog;??
08.import android.content.Context;??
09.import android.content.Intent;??
10.import android.content.SharedPreferences;??
11.import android.content.pm.PackageInfo;??
12.import android.content.pm.PackageManager;??
13.import android.content.pm.PackageManager.NameNotFoundException;??
14.import android.content.res.Resources;??
15.import android.os.Bundle;??
16.import android.os.Handler;??
17.import android.os.Message;??
18.import android.view.ContextMenu;??
19.import android.view.LayoutInflater;??
20.import android.view.MenuItem;??
21.import android.view.View;??
22.import android.view.ViewGroup;??
23.import android.view.ContextMenu.ContextMenuInfo;??
24.import android.view.View.OnCreateContextMenuListener;??
25.import android.widget.BaseAdapter;??
26.import android.widget.ImageView;??
27.import android.widget.ListView;??
28.import android.widget.TextView;??
29.import android.widget.Toast;??
30.import android.widget.AdapterView.AdapterContextMenuInfo;??
31.?
32.public class Main extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener{??
33.?
34.??? private ListView listview;??
35.??? private Context c;??
36.??? private Handler mHandler;??
37.??? private ProgressDialog pDialog;??
38.??? private SkinAdapter adapter;??
39.??? private SharedPreferences sp;??
40.??? static final int MESSAGE_SEARCHED_SKIN=0;??
41.??? static final int MESSAGE_SEARCHING_SKIN=MESSAGE_SEARCHED_SKIN+1;??
42.??? static final int MESSAGE_SEARCHED_SKIN_FOR_NONTHING=MESSAGE_SEARCHING_SKIN+1;??
43.?
44.??? @Override?
45.??? protected void onCreate(Bundle savedInstanceState) {??
46.?
47.??????? super.onCreate(savedInstanceState);??
48.??????? setContentView(R.layout.main);??
49.??????? init();??
50.??????? pDialog.show();??
51.??????? new Thread(serachSkin).start();??
52.?
53.??? }??
54.?
55.??? private void init()??
56.??? {??
57.?
58.??????? c=this;??
59.??????? mHandler=new Handler(){??
60.?
61.??????????? @Override?
62.??????????? public void handleMessage(Message msg) {??
63.??????????????? switch(msg.what)??
64.??????????????? {??
65.??????????????? case MESSAGE_SEARCHED_SKIN:??
66.??????????????????? ArrayList??
67. skins=(ArrayList??
68.) msg.obj;//获取skins??
69.??????????????????? adapter=new SkinAdapter(c, skins);??
70.??????????????????? listview.setAdapter(adapter);??
71.??????????????????? Toast.makeText(c, "查找到已经安装的皮肤", 1).show();??
72.??????????????????? pDialog.dismiss();??
73.??????????????????? break;??
74.??????????????? case MESSAGE_SEARCHED_SKIN_FOR_NONTHING:??
75.??????????????????? Toast.makeText(c, "未查找到任何皮肤", 1).show();??
76.??????????????????? pDialog.dismiss();??
77.??????????????? }??
78.??????????? }??
79.?
80.??????? };??
81.??????? sp=this.getSharedPreferences("config",Context.MODE_WORLD_WRITEABLE);??
82.??????? sp.registerOnSharedPreferenceChangeListener(this);??
83.?
84.??????? listview=(ListView) findViewById(R.id.list);??
85.??????? listview.setItemsCanFocus(false);??
86.??????? listview.setChoiceMode(ListView.CHOICE_MODE_SINGLE);??
87.?
88.??????? pDialog=new ProgressDialog(this);??
89.??????? pDialog.setMessage("正在查找已经安装的皮肤");??
90.?
91.??????? listview.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {??
92.?
93.??????????? public void onCreateContextMenu(ContextMenu menu, View v,??
94.??????????????????? ContextMenuInfo menuInfo) {??
95.??????????????? menu.add("使用该主题");??
96.?
97.??????????? }??
98.??????? });??
99.?
100.??? }??
101.?
102.??? private Runnable serachSkin =new Runnable(){??
103.?
104.??????? public void run() {??
105.??????????? PackageManager manager=c.getPackageManager();??
106.??????????? List??
107. packages=manager.getInstalledPackages(PackageManager.PERMISSION_GRANTED);??
108.?
109.??????????? ArrayList??
110. skins=new ArrayList??
111.();??
112.??????????? for(PackageInfo info:packages)??
113.??????????? {??
114.??????????????? //System.out.println(info.packageName);?
115.??????????????? if(info.packageName.startsWith("org.leepood.skin."))??
116.??????????????? {??
117.??????????????????? skins.add(info);??
118.??????????????? }??
119.??????????? }??
120.??????????? if(skins.size()>0)??
121.??????????? {??
122.??????????????? Message msg=mHandler.obtainMessage();??
123.??????????????? msg.obj=skins;??
124.??????????????? msg.what=MESSAGE_SEARCHED_SKIN;??
125.??????????????? mHandler.sendMessage(msg);??
126.??????????? }??
127.??????????? else?
128.??????????? {??
129.??????????????? mHandler.sendEmptyMessage(MESSAGE_SEARCHED_SKIN_FOR_NONTHING);??
130.??????????? }??
131.?
132.??????? }??
133.?
134.??? };??
135.??? private class SkinAdapter extends BaseAdapter??
136.??? {??
137.?
138.??????? LayoutInflater mInflater;??
139.??????? ArrayList??
140. datas;??
141.??????? PackageManager manager;??
142.??????? public SkinAdapter(Context c,ArrayList??
143. datas)??
144.??????? {??
145.?
146.??????????? this.datas=datas;??
147.???????????? mInflater=LayoutInflater.from(c);??
148.???????????? manager=c.getPackageManager();??
149.??????? }??
150.?
151.??????? public int getCount() {??
152.?
153.??????????? return datas.size();??
154.??????? }??
155.?
156.??????? public Object getItem(int position) {??
157.?
158.??????????? return datas.get(position);??
159.??????? }??
160.?
161.??????? public long getItemId(int position) {??
162.?
163.??????????? return 0;??
164.??????? }??
165.?
166.??????? public View getView(int position, View convertView, ViewGroup parent) {??
167.?
168.??????????? if(convertView==null)??
169.??????????? {??
170.??????????????? convertView=mInflater.inflate(R.layout.skin_item, null);??
171.??????????? }??
172.??????????? ImageView icon=(ImageView) convertView.findViewById(R.id.skin_icon);??
173.??????????? TextView? skin_name=(TextView) convertView.findViewById(R.id.skin_name);??
174.??????????? PackageInfo info=datas.get(position);??
175.??????????? icon.setImageDrawable(info.applicationInfo.loadIcon(manager));??
176.??????????? skin_name.setText(info.applicationInfo.loadLabel(manager));??
177.??????????? return convertView;??
178.??????? }??
179.?
180.??? }??
181.?
182.??? public void onThemeChanged(String newThemePackageName) {??
183.??????? try {??
184.?
185.??????????? Context themeContext=this.createPackageContext(newThemePackageName, CONTEXT_IGNORE_SECURITY);??
186.??????????? Resources res=themeContext.getResources();??
187.??????????? setControlsStyle(res);??
188.?
189.??????? } catch (NameNotFoundException e) {??
190.?
191.??????????? e.printStackTrace();??
192.??????? }??
193.?
194.??? }??
195.?
196.??? private void setControlsStyle(Resources res)??
197.??? {??
198.??????? listview.setBackgroundColor(res.getColor(R.color.ListView_bg));??
199.?
200.??? }??
201.?
202.??? @Override?
203.??? public boolean onContextItemSelected(MenuItem item) {??
204.??????? AdapterContextMenuInfo menuInfo=(AdapterContextMenuInfo)item.getMenuInfo();??
205.??????? PackageInfo info=(PackageInfo) adapter.getItem(menuInfo.position);??
206.?
207.??????? sp.edit().putString("themePackage", info.packageName).commit();??
208.??????? return super.onContextItemSelected(item);??
209.??? }??
210.?
211.??? public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,??
212.??????????? String key) {??
213.??????? System.out.println("themeChange");??
214.??????? onThemeChanged(sharedPreferences.getString(key, ""));??
215.?
216.??? }??
217.?
218.}
这段代码的含义就是去查找系统中安装的包名,若以org.leepood.skin.开头则说明该包为主题包,将其加入listview中显示出来。代码中使用了多线程避免时间过长堵塞UI。程序将当前主题配置保存在SharedPreference中,为SharedPreference注册了一个监听函数,当其值发生改变时自动调用新的样式。当然,这只是个demo而已,一开始加载Activity没有去读取主题,这个可以由大家自己去实现。
Android实现主题切换机制2
昨天花了点时间实现了主题的切换,但是里面还是不够灵活,回去想了想可以用继承和回调函数来进一步灵活更改主题,现在记录下我的实现办法
首先一个自定义类ThemeActivity继承自Activity,这个类是以后所有Activity的父类,在这个类里面定义了一个接口
public interface OnThemeChangedListener
{
public void onChanged(String newThemePackageName);
}
接下来,首先是要给ThemeActivity注册一个主题切换的listener,代码如下:
public void setOnThemeChangedListener(OnThemeChangedListener listener)
{
this.listener=listener;
}
然后就是注册一个SharedPreference来监听xml的变化,当发生改变的时候自动去调用listener.onChanged方法,将新的主题包名传递过去,代码如下:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if(key.equals("themePackage"))
{
listener.onChanged(sp.getString("themePackage", ""));
}
}
接着在继承于ThemeActivity的子类里面首先是setOnThemeChangedListener.接着用一个匿名内部类搞定。
?
?
注:博客涉及的源码请在千寻资源库:www.qxzyk.com 下载获取,谢谢支持。