在第一部分中我们创建了一个Settings界面并为之设置了主题,接下来我们将修复对话框布局和主题存在的问题。

点击EditTextPreference就会打开dialog。

因为从技术上说preference dialog其实就是 v7.app.AlertDialog,我们可以在 Activity的theme中用下面的入口把它的主题设置为Theme.AppCompat.DayNight.Dialog.Alert。

<item name="alertDialogTheme">
    @style/Theme.AppCompat.DayNight.Dialog.Alert
</item>

这个样式可以让dialog根据是否为日间或者夜间主题采用相应的颜色(关于如何设置DayNight主题,可以参考这里)。

当我们应用了DayNight theme之后,对话框是这个样子的,可以看到存在很多问题。

1-ckj1gZVaVCjTOwjy1m2ioQ.png

首先,dialog内容文字的颜色是白色的,且在一个白色的背景上。

其次,按钮使用了AppCompat默认的accentColor,而不是我们在主题中设置的accentColor。

最后一个问题是dialogMessage以及EditText没有足够的padding,离dialog的边界和标题太近。dialogMessage也是紧挨着标题,这看起来绝对不爽(这里文字是白色的看不出来)。

我在开发者选项中开启了显示布局边界,因此你可以看到所有元素的布局。

修复Dialog的布局

当你看了EditTextPreference的布局源码 (可以在这里找到)之后,可以看到他们为内容的LinearLayout应用了错误的padding。他们使用的是 android:padding=”5dip",这显然是不够的。而dialogMessage与EditText的距离设置为48dp,对我而言这太大了,我们最好把它值设置为其它的值。

正确的值我们可以参考 这里 的v7.app.AlertDialog的布局源码。可以看到左右padding用的是?attr/dialogPreferredPadding ,顶部padding用的是dimension abc_dialog_padding_top_material (18dp) 。

现在我们可以新建一个dimension资源,把它设置为18dp,以方便后面使用。

<dimen name="alert_def_padding">18dp</dimen>

完了之后我们从这里把EditText preference对话框的整个布局源码拷贝到一个新的布局 pref_dialog_edittext_fix.xml,然后修改padding和margin。

<ScrollView
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="48dp"
    android:layout_marginBottom="48dp"
    android:overScrollMode="ifContentScrolls">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/alert_def_padding"
        android:paddingBottom="@dimen/alert_def_padding"
        android:paddingStart="?dialogPreferredPadding"
        android:paddingLeft="?dialogPreferredPadding"
        android:paddingEnd="?dialogPreferredPadding"
        android:paddingRight="?dialogPreferredPadding"
        android:orientation="vertical">
        
        <TextView
            android:id="@android:id/message"
            style="?android:attr/textAppearanceSmall"
            android:layout_marginBottom="@dimen/alert_def_padding"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="?android:attr/textColorSecondary" />
        
        <EditText
            android:id="@android:id/edit"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        
    </LinearLayout>
</ScrollView>

我们可以为EditTextPreference添加android:dialogLayout 属性来改变对话框的布局:

<android.support.v7.preference.EditTextPreference
    android:key="key2"
    android:title="EditText Preference"
    android:summary="EditText Summary"
    android:dialogMessage="Dialog Message"
    android:defaultValue="Default value"
    android:dialogLayout="@layout/pref_dialog_edittext_fix" />

当然你可以往这个自定义布局中添加或者删除view,但要保证EditText的id为@android:id/edit,因为如果v7.preference library找不到它就会引起App的崩溃。同样,修复ListPreference对话框的布局也可以采用相同的方式。

现在对话框的对齐和padding看起来都很完美了。

1-g55zCzyYXs4mokF1b6e8kw.png

修复 Theme 和 Color

现在dialog中的按钮和文字的颜色仍然是不对的,我们来修复它。如果你想看看 AppCompat theme继承关系,你可以在 这里 找到源码。

修复按钮颜色

1-6AQ7QuJamFBnJVYJOkLVbQ.png

---在dialog主题中修改colorAccent前后的dialog

我们的dialog主题使用 DayNight.Dialog.Alert theme提供给的默认浅绿色覆盖了Acivity主题中设置的colorAccent,这就是为什么dialog的按钮没有使用Activity主题的colorAccent的原因。

如果我们想改变按钮颜色,我们需要修改dialog的主题。

为此我们在 styles.xml文件中使用下面的代码。首先新建一个名为AppAlertDialog的style,让它继承前面我们提到的dialog主题(DayNight.Dialog.Alert)。这样我们就可以把colorAccent改为我们想要的颜色。然后把Activity主题的alertDialogTheme设置为新创建的style。

<style name="AppTheme" parent="Theme.AppCompat">
    <!-- ... other stuff ... -->
    <item name="preferenceTheme">
        @style/PreferenceThemeOverlay.v14.Material
    </item>
    <item name="alertDialogTheme">@style/AppAlertDialog</item>
</style>
<style name="AppAlertDialog"
        parent="Theme.AppCompat.DayNight.Dialog.Alert">
    <item name="colorAccent">@color/colorAccent</item>
</style>

修复文字颜色

1-YpMkWb-yqo1uA8lijDtohQ.png

---修改内容布局主题前后的dialog

因为Activity的主题是 Theme.AppCompat,它的文字颜色是白色,而dialog主题没有覆盖这个颜色,所以在dialog中文字也为白色。我们可以在dialog主题中覆盖所有文字颜色,但这需要相当的工作量。而如果我们使用DayNight主题,工作量更大。

所以最简单的办法是对dialog的内容布局应用主题。

首先新建一个style,让它继承一个我们想要的主题。因为我们想让文字颜色做到根据是否为日间或者夜间主题自适应,所以这里我们让它继承Theme.AppCompat.DayNight。如果不使用DayNight主题,在夜间主题的时候可能会出现深色文字在深色背景上。但是Theme.AppCompat.DayNight主题不再继承Activity主题的colorAccent,所以这里还得再次添加colorAccent,让EditText保持目前的颜色。

<style name="AppAlertDialogContent"
        parent="Theme.AppCompat.DayNight">
    <!-- To keep the color of EditText -->
    <item name="colorAccent">@color/colorAccent</item>
</style>

现在回到pref_dialog_edittext_fix.xml文件,在它的根布局上添加我们创建的主题。

<ScrollView
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="48dp"
    android:layout_marginBottom="48dp"
    android:overScrollMode="ifContentScrolls"
    android:theme="@style/AppAlertDialogContent">

现在打开dialog,应该不再有任何问题了。如果还有问题,你也应该知道如何修改我们创建的样式和布局来解决了。

这是创建material design设置界面的第二步。下一部分我们将是关于如何自定义preferences以及如何解决这个过程中出现的问题。

第三部分见:https://www.aafxw.com/a/anzhuokaifa/androidkaifa/2017/0721/8221.html 

项目代码见 GitHub。

感谢阅读,祝编码愉快!