Android 反射实战 - 更换APP皮肤<1>

来源:互联网 发布:有趣的名字知乎 编辑:程序博客网 时间:2024/06/05 05:28

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的属性进行动态的更新替换.





0 0
原创粉丝点击