安卓theme與style詳解
阿新 • • 發佈:2019-02-18
安卓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那麼,不是有一個context,為什麼要重新生成一個ContextThemeWrapper呢。關於context點這裡,我們來看看這個ContextThemeWrapper。(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; }
/** * 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傳過去。