如何在android中探索样式

vel*_*lis 11 android styling

我正试图在Android中设置我的应用主题.但是,每个小部件本身都是一个令人痛苦的痛苦:我必须搜索主题特定小部件,然后创建一个样式,希望从小部件使用的相同样式派生.

当然,关于主题特定小部件的答案并不总是包含有关基本样式的信息,只包含特定颜色.

所以,不是接受鱼吃,你能教我钓鱼吗?

如何ObtainStyledAttributes()在窗口小部件构造函数中解释这些调用并从中提取样式?我该怎么说呢?

特别是,你能告诉我AlertDialog按钮颜色吗?什么样式定义棒棒糖扁平按钮+青色文字颜色?如果从AlertDialog源和ObtainStyledAttributes调用开始,我该如何获得该样式?

Vik*_*ram 33

我发现样式是关于通过框架解决问题的方式.该什么(几乎总是)来自控件的实现.在这里,我找到的是所有的地方.我将尽力通过您的特定用例 - AlertDialog的按钮来解释该过程.

开始:

您已经想到了这一点:我们从小部件的源代码开始.我们特意试图找到 - AlertDialog按钮获取文本颜色的位置.因此,我们从查看这些按钮的来源开始.它们是否在运行时显式创建?或者它们是在xml布局中定义的,它正在被夸大?

在源代码中,我们发现mAlert处理按钮选项等等:

public void setButton(int whichButton, CharSequence text, Message msg) {
    mAlert.setButton(whichButton, text, null, msg);
}
Run Code Online (Sandbox Code Playgroud)

mAlert是一个实例AlertController.在它的构造函数中,我们发现该属性alertDialogStyle定义了xml布局:

TypedArray a = context.obtainStyledAttributes(null,
            com.android.internal.R.styleable.AlertDialog,
            com.android.internal.R.attr.alertDialogStyle, 0);

    mAlertDialogLayout = 
            a.getResourceId(
            com.android.internal.R.styleable.AlertDialog_layout,
            com.android.internal.R.layout.alert_dialog);
Run Code Online (Sandbox Code Playgroud)

所以,我们应该看的布局是alert_dialog.xml- [sdk_folder]/platforms/android-21/data/res/layout/alert_dialog.xml:

布局xml很长.这是相关部分:

<LinearLayout>

....
....

<LinearLayout android:id="@+id/buttonPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="54dip"
    android:orientation="vertical" >
    <LinearLayout
        style="?android:attr/buttonBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:paddingTop="4dip"
        android:paddingStart="2dip"
        android:paddingEnd="2dip"
        android:measureWithLargestChild="true">
        <LinearLayout android:id="@+id/leftSpacer"
            android:layout_weight="0.25"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:visibility="gone" />
        <Button android:id="@+id/button1"
            android:layout_width="0dip"
            android:layout_gravity="start"
            android:layout_weight="1"
            style="?android:attr/buttonBarButtonStyle"
            android:maxLines="2"
            android:layout_height="wrap_content" />
        <Button android:id="@+id/button3"
            android:layout_width="0dip"
            android:layout_gravity="center_horizontal"
            android:layout_weight="1"
            style="?android:attr/buttonBarButtonStyle"
            android:maxLines="2"
            android:layout_height="wrap_content" />
        <Button android:id="@+id/button2"
            android:layout_width="0dip"
            android:layout_gravity="end"
            android:layout_weight="1"
            style="?android:attr/buttonBarButtonStyle"
            android:maxLines="2"
            android:layout_height="wrap_content" />
        <LinearLayout android:id="@+id/rightSpacer"
            android:layout_width="0dip"
            android:layout_weight="0.25"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:visibility="gone" />
    </LinearLayout>
Run Code Online (Sandbox Code Playgroud)

我们现在知道按钮获得属性所持有的样式buttonBarButtonStyle.

前往[sdk_folder]/platforms/android-21/data/res/values/themes.material.xml并搜索buttonBarButtonStyle:

<!-- Defined under `<style name="Theme.Material">` -->
<item name="buttonBarButtonStyle">@style/Widget.Material.Button.ButtonBar.AlertDialog</item>

<!-- Defined under `<style name="Theme.Material.Light">` -->
<item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
Run Code Online (Sandbox Code Playgroud)

根据您的活动的父主题是什么,buttonBarButtonStyle将参考这两种样式之一.现在,让我们假设您的活动的主题延伸Theme.Material.我们来看看@style/Widget.Material.Button.ButtonBar.AlertDialog:

打开[sdk_folder]/platforms/android-21/data/res/values/styles_material.xml并搜索Widget.Material.Button.ButtonBar.AlertDialog:

<!-- Alert dialog button bar button -->
<style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored">
    <item name="minWidth">64dp</item>
    <item name="maxLines">2</item>
    <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
Run Code Online (Sandbox Code Playgroud)

好的.但是这些值无助于我们确定按钮的文本颜色.我们应该看下一个父样式 - Widget.Material.Button.Borderless.Colored:

<!-- Colored borderless ink button -->
<style name="Widget.Material.Button.Borderless.Colored">
    <item name="textColor">?attr/colorAccent</item>
    <item name="stateListAnimator">@anim/disabled_anim_material</item>
</style>
Run Code Online (Sandbox Code Playgroud)

最后,我们发现textColor- 和它的attr/colorAccent初始化提供Theme.Material:

<item name="colorAccent">@color/accent_material_dark</item>
Run Code Online (Sandbox Code Playgroud)

对于Theme.Material.Light,colorAccent定义为:

<item name="colorAccent">@color/accent_material_light</item>
Run Code Online (Sandbox Code Playgroud)

浏览[sdk_folder]/platforms/android-21/data/res/values/colors_material.xml并找到这些颜色:

<color name="accent_material_dark">@color/material_deep_teal_200</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>

<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_500">#ff009688</color>
Run Code Online (Sandbox Code Playgroud)

AlertDialog的屏幕截图和相应的文本颜色:

在此输入图像描述

捷径:

有时,它更容易读取颜色值(如上图所示)并使用AndroidXRef搜索它.这种方法在你的情况下不会有用,因为#80cbc4它只会指出它的强调色.您仍然需要找到Widget.Material.Button.Borderless.Colored并将其与属性绑定buttonBarButtonStyle.

更改按钮的文字颜色:

理想情况下,我们应该创建一个扩展Widget.Material.Button.ButtonBar.AlertDialog,覆盖其中的样式android:textColor,并将其分配给属性buttonBarButtonStyle.但是,这不起作用 - 您的项目将无法编译.这是因为Widget.Material.Button.ButtonBar.AlertDialog是非公共风格,因此无法扩展.您可以通过检查链接来确认这一点.

我们将做下一个最好的事情 - 扩展父母的风格Widget.Material.Button.ButtonBar.AlertDialog- Widget.Material.Button.Borderless.Colored这是公开的.

<style name="CusButtonBarButtonStyle" 
       parent="@android:style/Widget.Material.Button.Borderless.Colored">
    <!-- Yellow -->
    <item name="android:textColor">#ffffff00</item>

    <!-- From Widget.Material.Button.ButtonBar.AlertDialog -->
    <item name="android:minWidth">64dp</item>
    <item name="android:maxLines">2</item>
    <item name="android:minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
Run Code Online (Sandbox Code Playgroud)

请注意,我们在覆盖后再添加3个项目android:textColor.这些都来自非公共风格Widget.Material.Button.ButtonBar.AlertDialog.由于我们无法直接扩展它,因此我们必须包含它定义的项目.注意:必须查找维度值并将其转移到项目中的相应res/values(-xxxxx)/dimens.xml文件中.

该样式CusButtonBarButtonStyle将分配给属性buttonBarButtonStyle.但问题是,AlertDialog将如何知道这一点?从源代码:

protected AlertDialog(Context context) {
    this(context, resolveDialogTheme(context, 0), true);
}
Run Code Online (Sandbox Code Playgroud)

传递0作为第二个参数resolveDialogTheme(Context, int)将最终在该else条款中:

static int resolveDialogTheme(Context context, int resid) {
    if (resid == THEME_TRADITIONAL) {
        ....
    } else {
        TypedValue outValue = new TypedValue();
        context.getTheme().resolveAttribute(
                com.android.internal.R.attr.alertDialogTheme,
                outValue, true);
        return outValue.resourceId;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们现在知道主题是由alertDialogTheme属性持有的.接下来,我们看看有什么意义alertDialogTheme.此属性的值取决于您的活动的父主题.浏览到你的sdk文件夹,找到values/themes_material.xml里面的android-21.搜索alertDialogTheme.结果:

<!-- Defined under `<style name="Theme.Material">` -->
<item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>

<!-- Defined under `<style name="Theme.Material.Light">` -->
<item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>

<!-- Defined under `<style name="Theme.Material.Settings">` -->
<item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
Run Code Online (Sandbox Code Playgroud)

因此,根据您的活动的基本主题,alertDialogTheme将保留这3个值中的一个.要让AlertDialog知道CusButtonBarButtonStyle,我们需要覆盖alertDialogTheme应用主题中的属性.比如说,我们使用的Theme.Material是基本主题.

<style name="AppTheme" parent="android:Theme.Material">
    <item name="android:alertDialogTheme">@style/CusAlertDialogTheme</item>
</style>
Run Code Online (Sandbox Code Playgroud)

从上面,我们知道alertDialogTheme指出Theme.Material.Dialog.Alert 你的应用程序的基本主题是什么时候Theme.Material.所以,CusAlertDialogTheme应该Theme.Material.Dialog.Alert作为其父母:

<style name="CusAlertDialogTheme" 
       parent="android:Theme.Material.Dialog.Alert">
    <item name="android:buttonBarButtonStyle">@style/CusButtonBarButtonStyle</item>
</style> 
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述

所以,不是接受鱼吃,你能教我钓鱼吗?

至少,我希望能解释鱼的位置.

PS我意识到我已经发布了一个猛犸象.

  • 哇,哇.这是我想象中的混乱.谷歌仍然需要学习很多关于API开发的知识:(至少材料试图解决这些问题.现在,看看我是否可以将我在这里学到的东西翻译成我实际使用的Appcompat主题. (2认同)