載入自定義屬性實現app換膚功能
阿新 • • 發佈:2019-01-03
在各大app中的換膚換主題的功能實現。博主的理解就是一種當用戶點選更換主題按鈕,從伺服器下載主題。這種就是外掛化載入。另一種就是自定義多套的屬性,當用戶點選的時候,就通過反射機制,在達到更換主題面板的效果。
下面,就通過一個小例子來實現換膚的功能,初次嘗試,如有紕漏的地方望大神指出,多多交流。
1:在values資料夾下新建attr.xml檔案(這裡就拿顏色變化來說,當然也可以定義圖片資源。)
2:在styles.xml中定義2套主題(裡面的color值我用漢語拼音寫的,通俗易懂)<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="main_bg" format="reference|color"/> <attr name="main_textcolor" format="reference|color"/> <attr name="other_bg" format="reference|color"/> <attr name="other_textcolor" format="reference|color"/> </resources>
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- 主題A --> <style name="theme_a" > <item name="main_bg">@color/bai</item> <item name="main_textcolor">@color/hei</item> <item name="other_bg">@color/bai</item> <item name="other_textcolor">@color/hei</item> </style> <!-- 主題B --> <style name="theme_b" > <item name="main_bg">@color/hei</item> <item name="main_textcolor">@color/bai</item> <item name="other_bg">@color/hei</item> <item name="other_textcolor">@color/bai</item> </style> </resources>
3:maniactivity的佈局檔案layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="?attr/main_bg" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin"> <Button android:id="@+id/btn_a" android:text="跳轉" android:layout_centerInParent="true" android:textColor="?attr/main_textcolor" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn_b" android:layout_centerHorizontal="true" android:text="換膚" android:layout_below="@id/btn_a" android:layout_marginTop="30dip" android:textColor="?attr/main_textcolor" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
注意其中自定義屬性的引用:
android:textColor="?attr/main_textcolor"
效果圖:
兩個按鈕,跳轉是跳到另一個activity中。來模擬點選換膚的時候app其他的頁面是否也做了變換。
另一個activity的佈局很簡單,這裡直接給出效果圖
這裡注意仔細看,預設的顏色第一個activity背景是白色,按鈕上面的字型顏色是黑色,第二個activity背景是白色,字型顏色是黑色
3:在來看activity類的程式碼
/**
* Created by W61 on 2016/11/25.
*/
public class BaseActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SpUtils.init(this, "henry_theme");
if(SpUtils.getInt("theme", 0) == 1) {
setTheme(R.style.theme_b);
} else {
setTheme(R.style.theme_a);
}
}
}
public class MainActivity extends BaseActivity {
private Button btn_a,btn_b;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
btn_a = (Button) findViewById(R.id.btn_a);
btn_a.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this,OtherActivity.class));
}
});
btn_b = (Button) findViewById(R.id.btn_b);
btn_b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(SpUtils.getInt("theme", 0) == 1) {
SpUtils.setInt("theme", 0);
setTheme(R.style.theme_a);
} else {
SpUtils.setInt("theme", 1);
setTheme(R.style.theme_b);
}
final View rootView = getWindow().getDecorView();
ColorUiUtil.changeTheme(rootView, getTheme());
startActivity(new Intent(MainActivity.this,MainActivity.class));
finish();
}
});
}
建了一個baseactivity便於統一管理,sputils是儲存當前到底是那套面板的標識。大家可以自由發揮
注意:
startActivity(new Intent(MainActivity.this,MainActivity.class));
finish();
博主這個寫這句程式碼是想點選換膚後當前頁面也隨之重新整理。這裡如果大家有更好的方法可以留言指出。
下面是一個幫助類(這個類拷貝網上大神寫的方法)
/**
* Created by chengli on 15/6/10.
*/
public class ColorUiUtil {
/**
* 切換應用主題
*
* @param rootView
*/
public static void changeTheme(View rootView, Resources.Theme theme) {
if (rootView instanceof ColorUiInterface) {
((ColorUiInterface) rootView).setTheme(theme);
if (rootView instanceof ViewGroup) {
int count = ((ViewGroup) rootView).getChildCount();
for (int i = 0; i < count; i++) {
changeTheme(((ViewGroup) rootView).getChildAt(i), theme);
}
}
if (rootView instanceof AbsListView) {
try {
Field localField = AbsListView.class.getDeclaredField("mRecycler");
localField.setAccessible(true);
Method localMethod = Class.forName("android.widget.AbsListView$RecycleBin").getDeclaredMethod("clear", new Class[0]);
localMethod.setAccessible(true);
localMethod.invoke(localField.get(rootView), new Object[0]);
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e2) {
e2.printStackTrace();
} catch (NoSuchMethodException e3) {
e3.printStackTrace();
} catch (IllegalAccessException e4) {
e4.printStackTrace();
} catch (InvocationTargetException e5) {
e5.printStackTrace();
}
}
} else {
if (rootView instanceof ViewGroup) {
int count = ((ViewGroup) rootView).getChildCount();
for (int i = 0; i < count; i++) {
changeTheme(((ViewGroup) rootView).getChildAt(i), theme);
}
}
if (rootView instanceof AbsListView) {
try {
Field localField = AbsListView.class.getDeclaredField("mRecycler");
localField.setAccessible(true);
Method localMethod = Class.forName("android.widget.AbsListView$RecycleBin").getDeclaredMethod("clear", new Class[0]);
localMethod.setAccessible(true);
localMethod.invoke(localField.get(rootView), new Object[0]);
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e2) {
e2.printStackTrace();
} catch (NoSuchMethodException e3) {
e3.printStackTrace();
} catch (IllegalAccessException e4) {
e4.printStackTrace();
} catch (InvocationTargetException e5) {
e5.printStackTrace();
}
}
}
}
下面來看最終執行圖:
大家可以仔細觀察點選換膚前和換膚後的背景顏色和字型顏色。
這裡建議大家在點選換膚時彈出一個載入框。來緩衝一下當前介面的重新整理。