Android Dialog custom Theme
解决思路:
一.查看dialog的构造器如下图1-1、1-2
/** * Create a Dialog window that uses a custom dialog style. * * @param context The Context in which the Dialog should run. In particular, it * uses the window manager and theme from this context to * present its UI. * @param theme A style resource describing the theme to use for the * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style * and Theme Resources</a> for more information about defining and using * styles. This theme is applied on top of the current theme in * <var>context</var>. If 0, the default dialog theme will be used. */ public Dialog(Context context, int theme) { this(context, theme, true); }
图1-1
Dialog(Context context, int theme, boolean createContextWrapper) { if (theme == 0) { TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, outValue, true); theme = outValue.resourceId; } mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context; mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); Window w = PolicyManager.makeNewWindow(mContext); mWindow = w; w.setCallback(this); w.setWindowManager(mWindowManager, null, null); w.setGravity(Gravity.CENTER); mUiThread = Thread.currentThread(); mListenersHandler = new ListenersHandler(this); }
图1-2
发现,我们可以指定Dialog的主题。问题很简单是不是就解决了呢?答案是不一定,原因是:
二、Dialog的结构包括三部分:title、content area、action buttons。对于title和action buttons 没什么好说的,直接调用系统的Api就行,而对于content area就不一样了,
1.你可以直接调用系统的Api设置内容,指定的主题应该也会应用上去(没有严格验证)。
2.也可以自定义内容,这个时候就要注意了。对于自定义的内容就不能应用到指定的theme了。
对于自定义内容的一般会这样调用LayoutInflater.from(context).inflate(...),而context中是有主题内容的context中settheme如下图1-3
/** * Set the base theme for this context. Note that this should be called * before any views are instantiated in the Context (for example before * calling {@link android.app.Activity#setContentView} or * {@link android.view.LayoutInflater#inflate}). * * @param resid The style resource describing the theme. */ public abstract void setTheme(int resid);
图1-3
如源码中所说,设置主题一定要早于setcontentview 和 layoutinflater inflate。所以,我们推测,在dialog中自定义content area ,并用LayoutInflater.from(context).inflate(...)装载view时,view就会用context'中得主题。问题来了,如果想对dialog中自定义的content area怎么应用theme呢?
看图1-1,当指定dialog的主题后,会调用图1-2中得方法,mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context;
也就是 mContext = new ContextThemeWrapper(context, theme) ,所以我们推测,可以在原context的基础上调用new ContextThemeWrapper(context, theme)生成带有指定theme的新的context,新的context'与原有context仅有theme不一样,这样一来。
三、我们就可以通过
AlertDialog.Builder builder = new Builder(context);
ContextThemeWrapper themeContext = new ContextThemeWrapper(context, theme);
LayoutInflater.from(themeContext).inflate(...)
来让自定义content area 的dialog 应用指定主题。
四、对于activity中显示的dialog,还用一种简单的方法来让dialog(不管是否自定义content area)应用指定theme,那就是设置activity的theme即可。
但是原理和上面的一样,不再赘述。