Android 动态更换APP皮肤,个人感觉更多的是开发者对View理解能力,以及Activity等这种容器是如何加载各种视图view的过程,这个view包括系统UI,自定UI等view.这个地方首先就需要先熟悉Factory这个接口,看一看下面做一个测试工程:
<1> : 新建一个Android 工程项目,目录树如下:
<2> : OneplusFactoryImpl.java 类程序如下:
/**
*
*/
package impl;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater.Factory;
import android.view.LayoutInflater;
import android.view.View;
/**
* @author zhibao.liu
* @date 2015-12-8
* @company : oneplus.Inc
*/
public class OneplusFactoryImpl implements Factory {
private final static String TAG="oneplus";
/*
* (non-Javadoc)
*
* @see android.view.LayoutInflater.Factory#onCreateView(java.lang.String,
* android.content.Context, android.util.AttributeSet)
*/
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// TODO Auto-generated method stub
View view = createView(context, name, attrs);
return null;
}
private View createView(Context context, String name, AttributeSet attrs) {
View view = null;
Log.i(TAG,"create name : " + name);
try {
if (-1 == name.indexOf('.')) {
if ("View".equals(name)) {
view = LayoutInflater.from(context).createView(name,
"android.view.", attrs);
}
if (view == null) {
view = LayoutInflater.from(context).createView(name,
"android.widget.", attrs);
}
if (view == null) {
view = LayoutInflater.from(context).createView(name,
"android.webkit.", attrs);
}
} else {
view = LayoutInflater.from(context).createView(name, null,
attrs);
}
} catch (Exception e) {
Log.i(TAG, "error while create " + name + " : " + e.getMessage());
view = null;
}
return view;
}
}
做一个实现factory接口的类.
<2> : 再新建OneplusBaseActivity.java:
/**
*
*/
package com.oneplus.base;
import impl.OneplusFactoryImpl;
import java.lang.reflect.Field;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
/**
* @author zhibao.liu
* @date 2015-12-8
* @company : oneplus.Inc
*/
public class OneplusBaseActivity extends Activity {
private OneplusFactoryImpl mFactory;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
try {
Field field = LayoutInflater.class.getDeclaredField("mFactorySet");
field.setAccessible(true);
try {
field.setBoolean(getLayoutInflater(), false);
mFactory = new OneplusFactoryImpl();
getLayoutInflater().setFactory(mFactory);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
<3> : OneplusFactoryActivity主类继承上面的基类:
package com.oneplus.factoryimplapp;
import com.oneplus.base.OneplusBaseActivity;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
/**
*
*/
/**
* @author zhibao.liu
* @date 2015-12-8
* @company : oneplus.Inc
*/
public class OneplusFactoryActivity extends OneplusBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.oneplus_factory);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.oneplus_factory, menu);
return true;
}
}
然后运行上面程序,结果如下:
一眼看不出来,但是仔细看一下,这个APP所有继承OneplusBaseActivity基类用到的UI信息都包含在里面了,设置包括状态栏.如果还不能够立即,我们在主类的布局增加一个上面没有的一个View,如果Button UI :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".OneplusFactoryActivity" >
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/button"
android:layout_below="@id/text"
android:text="hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
截取其中一部分结果如下:
也就是说,通过上面的方法,在实现Factory接口的类中,可以获取出所有APP中包含的所有UI的种类和属性,我们获取了他们信息,就可以在APP启动的时候,获取并且保存起来,一边供后面获取资源后对所有UI的属性进行动态的更新替换.