现在android上主流的换肤方式大致以后三种:
1.皮肤都内置于应用程序apk资源文件内,这种实现相对较容易,但是灵活性欠缺,对apk大小也有影响。比如qq的换肤功能。
2.皮肤以apk安装包形式提供,比如go桌面的主题实现,本文即讨论这种实现。
3.以zip文件提供,如墨迹天气等的换肤实现。
下面主要讨论第二种实现,即将皮肤作为单独的apk安装。
思路:主程序扫描皮肤程序,读取皮肤程序的资源并设置为属性。
效果图如下:
Skin01是单独安装的皮肤apk。背景图片是Skin01里面的资源,这里的换肤示例效果就是将主程序的背景换掉。
需要解决的问题是如何扫描到皮肤文件。这里我们用sharedUserId可以巧妙的解决问题,顾名思义,sharedUserId相同的应用运行在同一个进程里,可以随意相互访问数据。sharedUserId在AndroidManifest.xml中配置,这里我们将主应用程序和所有皮肤文件的sharedUserId均设置为android:sharedUserId="com.cienet.testplugin"
背景图片资源在Skin01下的drawable里,命名为pic.png,主程序要引用Skin01里面的资源需要在主程序中添加代替的文件,比如引用Skin01中drawable下的pic.png就需要在主程序中的drawable下放置一张名为pic.png的图片。主程序调用皮肤apk的资源方法如下:
Context context = createPackageContext("perfecter.skin01",
Context.CONTEXT_IGNORE_SECURITY);
Drawable drawable = context.getResources().getDrawable(R.drawable.pic);
取到皮肤apk的Context之后就和取资源的操作一样了。
(2012.08.03补充:刚才群里一个朋友说我这里只是读取了apk的一张图片,他要实现天天动听那样的效果。天天动态的不同皮肤布局不同,其实我们上面得到皮肤的Context了,也可以得到皮肤的布局啊,拿到之后直接设置到主程序也行啊。)
补充代码如下:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try
{
context = createPackageContext("perfecter.skin01",
Context.CONTEXT_IGNORE_SECURITY);
}
catch (NameNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Button bt=(Button)findViewById(R.id.button1);
bt.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
View vv=LayoutInflater.from(context).inflate(R.layout.main, null);
setContentView(vv);
}
});
}
demo工程下载地址:http://download.csdn.net/detail/lg707415323/4410863