1. 程式人生 > >安卓theme與style詳解

安卓theme與style詳解

   安卓app作為一個有介面的程式,谷歌給我們提供了很多UI控制元件。而控制元件是功能性的,具體的控制元件樣式卻是需要我們自己去控制的。這也就引出了今天話題,安卓的theme與style。說到這個,大家可能都知道theme是主題,也就是整個app的樣式。而style是樣式,控制的是單個View。是的,希望我們在應用的時候也要銘記這點。

也就是說theme是針對application和activity的,當然也不是所有都是這樣的,比如toolbar就可以設定theme。一開始toolbar是特例,但後來谷歌推出了ThemeOverlay使得一般view也可以使用theme。而且會傳遞給子控制元件。theme原理是什麼呢,我們來看看View的構造方法。

public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    this(context);
    final TypedArray a = context.obtainStyledAttributes(
            attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
可以看到是使用的context物件得到的屬性陣列,這也是所有的View構造方法要包含context的原因。
具體引數意義及作用順序
,你也可以直接看裡面結論就好了。

其實控制theme不難,難的是控制一個view的style,因為它跟theme還有關係。比如現在我改變了一個activity的theme,我如何讓裡面的View用原theme的樣式呢?為了回答這個問題,我們先來看Dialog原始碼。因為Dialog是可以設定Theme的,而且不影響原來的activity。

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    if (createContextThemeWrapper) {          if 
(themeResId == 0) { final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); themeResId = outValue.resourceId; } mContext = new ContextThemeWrapper(context, themeResId); //可以看到true時,會建立一個這種物件} else { mContext = context; }
那麼,不是有一個context,為什麼要重新生成一個ContextThemeWrapper呢。關於context點這裡,我們來看看這個ContextThemeWrapper
/**
 * A ContextWrapper that allows you to modify the theme from what is in the 
 * wrapped context. 
 */
public class ContextThemeWrapper extends ContextWrapper {
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;
    private Configuration mOverrideConfiguration;
    private Resources mResources;
    public ContextThemeWrapper() {
        super(null);
}

    public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
        super(base);
mThemeResource = themeResId;
}

    public ContextThemeWrapper(Context base, Resources.Theme theme) {
        super(base);
mTheme = theme;
}..............
可以看到重寫了theme相關的方法和屬性,而且從類的介紹也可以看出。回到原來的問題,我們可以通過new一個這個類的物件給View傳過去。