`
phenom
  • 浏览: 409713 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

android theme 皮肤主题 的应用

阅读更多
如今的程序猿,当然先从网上搜索一番了。关于皮肤的制作 ,主要有三种,似乎所有 的文章都是从一处抄来的。

我也顺便抄了一段:其中以apk安装版本的为例子。
shareuserid这个东西,由实践得出结论,不是用在这里的,没有也没关系。

创建相关的Context:
Context context = createPackageContext("com.yuchen.customskin"
            Context.CONTEXT_IGNORE_SECURITY);
前面的包名,你自己想办法 弄到了。
有了这个东西,就可以处理相关的界面了。比如:Drawable drawable = context.getResources().getDrawable(R.drawable.bg);

这段就是网上常见的东西了。

这里说一些个人实践得出的一些结果。
有些程序是先载入布局,然后对里面的背景,图片等资源,重新加载一次,就是用上面的东西了。由createPackageContext创建一个对象,然后得到里面的资源。

这是一个办法,如果想直接得到布局呢:
Context ctxt=context.createPackageContext(packageName, Context.CONTEXT_IGNORE_SECURITY);
LayoutInflater inflater = LayoutInflater.from(ctxt);
然后用这个inflater来加载,最常用的就是Fragment了。
String themeName = prefsWrapper.getPreferenceStringValue(SipConfigManager.THEME);//从sp设置中得到主题的名字,可以以存储在其它地方,如数据库。。。
        Log.d(THIS_FILE, "prefsWrapper themeName:"+themeName);
        if (!TextUtils.isEmpty(themeName)) {
            Theme theme=new Theme(getActivity(), themeName, null);
            View view=theme.getLayoutResource(getActivity(), container, "com.packageName:layout/a_fragment");
            if(null!=view) {
            	return view;
            }
        }
        return inflater.inflate(resId, container, false);

这样就可以直接在onCreateView载入布局了,而不必在载入后再对其中的按钮,文本。。。进行处理了。

在csipsimple代码中有一段是关于主题的,但它是使用异步加载。
查询当前所有的相关主题 apk安装包:
public static HashMap<String, String> getAvailableThemes(Context ctxt){
		HashMap<String, String> result = new HashMap<String, String>();
		result.put(ctxt.getResources().getString(R.string.app_name), "");
		
		PackageManager packageManager = ctxt.getPackageManager();
		Intent it = new Intent(SipManager.ACTION_GET_DRAWABLES);
		
		List<ResolveInfo> availables = packageManager.queryBroadcastReceivers(it, 0);
		Log.d(THIS_FILE, "We found " + availables.size() + "themes");
		for(ResolveInfo resInfo : availables) {
			Log.d(THIS_FILE, "We have -- "+resInfo);
			ActivityInfo actInfos = resInfo.activityInfo;
			String packagedActivityName = actInfos.packageName + "/" + actInfos.name;
			Log.d(THIS_FILE, "packagedActivityName:"+packagedActivityName);
			result.put((String) resInfo.loadLabel(packageManager), packagedActivityName);
		}
		
		return result;
	}
在皮肤apk名是只有一个ThemeReceiver,这个接收的字符串固定是
	public static final String ACTION_GET_DRAWABLES = "com.csipsimple.themes.GET_DRAWABLES";
,
于是我下载了一个皮肤 :com.csipsimple.themes.froyo
可惜,不能用。
查询的结果,只是在选择主题时候用到。

应用 主题 :它是在onresume里面调用的。可想而知,如果是这样,每次恢复 都会调用一次,也挺耗资源的。
String theme = prefsWrapper.getPreferenceStringValue(SipConfigManager.THEME);
        Log.d(THIS_FILE, "prefsWrapper theme:"+theme);
        if (!TextUtils.isEmpty(theme)) {
new Theme(getActivity(), theme, new Theme.onLoadListener() {
                @Override
                public void onLoad(Theme t) {

                    dialPad.applyTheme(t);
                     t.applyBackgroundDrawable(getView().findViewById(R.id.vmButton),
                            "btn_dial_action_left_normal");
...... 这里是异步处理的,程序运行的结果是先看到原始界面,然后调用这个方法异步处理后,界面会发生变化。
                }
            });
}

public Theme(Context ctxt, String packageName, onLoadListener l) {
		listener = l;
		pm = ctxt.getPackageManager();
		
		String[] splitPackage = packageName.split("/");
		ComponentName cn = new ComponentName(splitPackage[0], splitPackage[1]);
		
		Intent it = new Intent(SipManager.ACTION_GET_DRAWABLES);
		it.setComponent(cn);
		
		ctxt.sendOrderedBroadcast(it, null, new BroadcastReceiver() {
			@Override
			public void onReceive(Context context, Intent intent) {
				resolvedInfos = getResultExtras(true);
				Log.d(THIS_FILE, "We have logs : " + resolvedInfos.size());
				Iterator<String> it=resolvedInfos.keySet().iterator();
				while (it.hasNext()) {
					String val=it.next();
					Log.d(THIS_FILE, "key:"+val);
				}
				if(listener != null) {
					listener.onLoad(Theme.this);
				}
			}
		}, null, Activity.RESULT_OK, null, null);

		Log.d(THIS_FILE, "After broadcast" );
			
	}

为什么前面的皮肤froyo不能用呢?因为onReceive方法没有内容。所以resolvedInfos.size()=0.
文档中说sendOrderedBroadcast里面的BroadcastReceiver.getResultExtras方法接收上一次的结果。由于前面的onReceive没有返回东西,所以这里也接收不到。
于是下载源码修改了:
if(ACTION_GET_DRAWABLES.equalsIgnoreCase(intent.getAction())) {
			Bundle bundle=new Bundle();
			bundle.putString("dial_num_0", "com.csipsimple.themes.froyo:drawable/dial_num_0");
			bundle.putString("dial_num_1", "com.csipsimple.themes.froyo:drawable/dial_num_1");
			bundle.putString("dial_num_2", "com.csipsimple.themes.froyo:drawable/dial_num_2");
			bundle.putString("dial_num_3", "com.csipsimple.themes.froyo:drawable/dial_num_3");
			bundle.putString("dial_num_4", "com.csipsimple.themes.froyo:drawable/dial_num_4");
			bundle.putString("dial_num_5", "com.csipsimple.themes.froyo:drawable/dial_num_5");
			bundle.putString("dial_num_6", "com.csipsimple.themes.froyo:drawable/dial_num_6");
			bundle.putString("dial_num_7", "com.csipsimple.themes.froyo:drawable/dial_num_7");
			bundle.putString("dial_num_8", "com.csipsimple.themes.froyo:drawable/dial_num_8");
			bundle.putString("dial_num_9", "com.csipsimple.themes.froyo:drawable/dial_num_9");

			bundle.putString("btn_dial_press", "com.csipsimple.themes.froyo:drawable/btn_dial_press");
			bundle.putString("btn_dial_normal", "com.csipsimple.themes.froyo:drawable/btn_dial_normal");
			bundle.putString("btn_dial_action_left_normal", "com.csipsimple.themes.froyo:drawable/btn_dial_action_left_normal");
			bundle.putString("dial_num_star", "com.csipsimple.themes.froyo:drawable/dial_num_star");

			bundle.putString("call_log_fragment", "com.csipsimple.themes.froyo:layout/call_log_fragment");
			setResultExtras(bundle);
		}
先把一些东西放进去,没有写全部的。

然后就可以看到效果了。

从上面也可以看到一些缺点,就是ui的应用,在第一次启动程序时,会有两次变化,一次是原始的皮肤,一次是应用后的新皮肤,而且需要在onReceive里面写一堆相关的包名+资源名。(当然这一步可能可以优化下,比如可以在oncreate的setcontentview载入后只设置一次,这样修改皮肤 就需要重启这个activity了。)

个人还是比较倾向于载入布局,这样就可以连带其它资源的载入了。不用一个一个地设置图片。如果没有修改ActionBar就还好,如果有的话,就麻烦一点,需要单独地处理ActionBar的资源。

从csipsimple中的代码可以了解:
查询安装的皮肤是可以通过一个receiver来处理的,而网上流传的版本普遍是通过shareuserid。对于 onreceive里面是否有返回一些数据,可能只是csipsimple有必要。而且试过了:

public View getLayoutResource(Context context,ViewGroup container,String name) {
		//if(resolvedInfos != null) {
			String layoutName =name;// resolvedInfos.getString(name);
			Log.d(THIS_FILE, "getLayoutResource:"+layoutName+" name:"+name);
			if(layoutName != null) {
				Log.d(THIS_FILE, "Theme package we search for " + layoutName);
				
				String packageName = layoutName.split(":")[0];
				
				//Log.d(THIS_FILE, "Theme package we search for " + packageName);
				
				PackageInfo pInfos;
				try {
					pInfos = pm.getPackageInfo(packageName, 0);
					Log.d(THIS_FILE, "pInfos.packageName:"+pInfos.packageName);
					Resources remoteRes = pm.getResourcesForApplication(pInfos.applicationInfo);
					int id = remoteRes.getIdentifier(layoutName, null, null);
					Log.d(THIS_FILE, "id:"+id);
					if(id!=0) {
						Context ctxt=context.createPackageContext(packageName, Context.CONTEXT_IGNORE_SECURITY);
						LayoutInflater inflater = LayoutInflater.from(ctxt);
						return inflater.inflate(id, container, false);
					}
				} catch (NameNotFoundException e) {
					Log.e(THIS_FILE, "Unable to get resources for this theme package");
				}
			}else {
				Log.w(THIS_FILE, "Theme is not complete, not found : "+name);
			}
		/*}else {
			Log.d(THIS_FILE, "No results yet !! ");
		}*/
		return null;
	}
然后在Fragment的oncreateview中应用,是可以得到这个布局的。这也取消了前面的设置返回值,当然布局文件名在皮肤的apk中要一致,以免找不到资源。

在froyo中新建一个layout,用上面的代码 就可以载入了。

老外可能也不是很在意皮肤,不像国人,多数注重外表,所以关于皮肤的文章不多。froyo是旧系统的资源,而不是特定的某种皮肤 。


附件是apk可以先安装一个CSipSimpleTest.apk,看到第一个Fragment,拨号面板,与第二个Fragment的样子,然后再安装第二个apk,CSipSimpleThemeFroyo.apk再看看样子。是不同的。
虽然丑了点,此示例主要在于测试。

如果只是修改同一个apk中不同的主题 可以这样:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        Context darkTheme = new ContextThemeWrapper(getActivity(), R.style.AppTheme_Dark_NoActionBar);

        inflater = LayoutInflater.from(darkTheme);

        return inflater.inflate(R.layout.awesome_fragment, container, false);

    },这段是创建了主题相关的Context,然后再应用。如果应用内的皮肤,也不必这样麻烦了,可以直接 设置Activity的theme的style了。

源码以后附上。

先记录到此吧。以后补充。







分享到:
评论
3 楼 phenom 2013-08-06  
yangmaolinpl 写道
楼主,你这个有没有源码,发兄弟下,谢谢!!帖子上的zip文件下不下来。358003548@qq.com

是下载不了,包没有了.硬盘已经换了.你可以下载csipsimple的源码看下.
2 楼 yangmaolinpl 2013-08-06  
楼主,你这个有没有源码,发兄弟下,谢谢!!帖子上的zip文件下不下来。358003548@qq.com
1 楼 yangmaolinpl 2013-08-06  
学习!!写的挺详细的。

相关推荐

    android theme 皮肤主题 的应用 2

    2. **应用主题**:在AndroidManifest.xml中,对需要应用主题的Activity添加android:theme属性,引用自定义的主题风格。 3. **处理动态换肤**:如果需要支持动态换肤,可以使用第三方库如AndroSkin或DynamicTheme,...

    Android Theme更换主题换肤应用实例

    Android Theme界面换肤应用实例,也就是更改系统主题风格,可在“应用透明背景的主题”、“应用布景主题1”、“应用布景主题2”三种皮肤风格之间切换,Android换肤对Android手机来说是再简单不过的功能了,个性化...

    Android应用皮肤切换Demo

    - Android中的主题(Theme)也是实现皮肤的一种方式,通过在styles.xml文件中定义不同的主题,然后在AndroidManifest.xml中为Activity或整个应用设置不同的主题。 - 主题可以控制全局的颜色、字体样式等,但不适用...

    Android之主题皮肤实现

    主题(Theme)是Android系统提供的一种全局样式设定,它可以控制应用程序的整体外观,包括字体颜色、背景色、按钮样式等。皮肤(Skin)则是主题的一个变体,它允许用户根据个人喜好更改应用的视觉风格,而无需改变...

    android开发皮肤图片

    4. **自定义View**:对于更复杂的皮肤应用,可能需要创建自定义View,重写onDraw()方法,或者使用Nine-Patch图片来实现自适应边距和伸缩性。 5. **资源切换**:为了实现皮肤切换功能,可以在应用中设置一个设置页面...

    Android切换界面皮肤代码

    在Android开发中,实现界面皮肤切换的功能可以提升用户体验,让用户根据个人喜好自定义应用的视觉样式。本教程将深入探讨如何在Android应用中实现实时切换界面皮肤的代码技术。 首先,我们需要理解皮肤的基本概念。...

    Android 应用 更换皮肤(skin apk安装实现)

    在Android应用开发中,更换皮肤或主题是一种常见的用户定制化功能,可以提升用户体验,让用户根据个人喜好调整应用的视觉风格。本篇文章将深入探讨如何在Android应用中实现皮肤更换,特别是通过skin APK安装来实现这...

    android app皮肤更换方案

    在Android应用开发中,皮肤更换方案是一个常见的需求,它允许用户根据个人喜好定制应用的外观。这个主题涉及到多个技术层面,包括资源管理、主题切换、动态加载等方面。下面将详细探讨如何实现Android App的皮肤更换...

    Android主题开发

    通过在AndroidManifest.xml文件中设置或标签的android:theme属性,可以应用主题。 二、自定义主题 1. 创建主题资源:在res/values/styles.xml文件中,开发者可以定义自己的主题。例如,创建一个名为"MyTheme"的...

    安卓开发更改皮肤功能,全局皮肤

    5. **主题支持**:全局皮肤更换功能往往与主题系统结合,Android提供了一套完整的主题框架,通过主题风格(Theme)可以统一控制整个应用的界面样式。开发者可以通过自定义主题,覆盖默认样式,实现皮肤更换。 6. **...

    android 皮肤demo

    总的来说,“android皮肤demo”是一个展示Android应用如何实现换肤功能的实例,它涵盖了主题设置、皮肤包加载以及第三方库的使用等多个方面。通过对这些知识点的理解和实践,开发者可以为用户提供更加个性化和丰富的...

    android仿QQ更换皮肤

    同时,可以在代码中动态设置View的样式,根据用户选择的皮肤应用相应的主题。 5. **图片处理**:QQ皮肤中可能包含背景图片,开发者需要考虑如何高效地加载和显示这些图片。Android提供了多种图片加载库,如Glide、...

    uniapp 实现更换主题皮肤

    在开发移动应用时,主题皮肤的可更换性是提升用户体验的重要功能之一。uniAPP作为一个跨端开发框架,允许开发者用一套代码实现多平台部署,包括iOS、Android、H5等。本文将详细介绍如何在uniAPP中实现主题皮肤的更换...

    android换肤demo1

    综上所述,“android换肤demo1”项目涵盖了Android应用开发中关于换肤的多个核心方面,从主题和样式的定义,到动态加载和切换皮肤,再到用户体验和兼容性的考虑,都是开发者需要掌握的重要知识点。通过研究这个示例...

    Android中设置屏幕的皮肤

    首先,皮肤在Android中通常指的是主题(Theme)或样式(Style)。它们定义了应用程序的整体视觉效果,包括颜色、字体、布局等。Android系统提供了多种内置主题,开发者也可以自定义主题以满足个性化需求。 1. **...

    Android软件换肤功能(AppTheme)

    4. **动态应用主题**:在用户选择新的皮肤后,我们不能简单地重启Activity来应用新主题,因为这会打断用户的交互体验。相反,我们可以通过调用`setTheme()`方法并在`onCreate()`之前设置新的主题来实现动态换肤。...

    Android应用源码安卓软件实现动态皮肤更换.zip

    2. **主题和样式**:利用Android的Theme和Style机制,开发者可以定义不同的皮肤主题,通过改变主题达到更换皮肤的效果。 3. **代码逻辑**:需要编写代码来处理皮肤的切换,包括读取皮肤文件、更新UI元素的样式等。 4...

    android 应用的换肤demo

    本文将详细解析"android应用的换肤demo",介绍如何利用Android的主题样式(style)来实现这一功能,以及如何通过更换主题来改变Activity背景、View属性,如背景色和字体颜色。 首先,理解Android的主题(Theme)和...

    Android 高仿点心桌面皮肤源码

    Android支持通过设置主题(Theme)改变应用的整体风格。开发者可能创建了自己的主题样式,包含颜色、字体、阴影等属性,并在代码中应用到各个组件上。例如,通过设置style.xml中的标签,可以改变按钮、文本框等元素...

Global site tag (gtag.js) - Google Analytics