有没有一种通用的方法来查找适用于View的样式?

时间:2015-09-03 10:48:44

标签: android android-styles

一般来说,为了改变任何UI元素的外观,您是如何找到要覆盖的主题属性的?

目前我依赖于遍历框架源文件:values.xml中的主题定义(通常是支持库变体),attrs.xml中的属性定义以及R.styleable类文档。

但这完全是一种机会。这不仅耗费时间,而且有时我会完全错过,例如我一直在努力寻找如何在DatePickerDialog的OK和Cancel按钮中更改文本样式。您可以随意使用它作为示例,但如果您这样做,请概述您的发现过程。我正在寻找的答案是如何发现任何UI元素的应用样式,

还是没有确定的方法可以找到答案?你只需要知道吗?

1 个答案:

答案 0 :(得分:6)

在Android上查找如何更改小部件的样式一直很麻烦。例如,DatePickerDialog具有不同的Holo和Material设计样式。因此,对话框的样式可能取决于SDK值,或者您使用的是AppCompat库。文档也很少。

如果像Hierarchy Viewer这样的工具显示属性和窗口小部件的当前主题,那就太好了。但是,我还没有遇到过这样的工具。

我们可以在创建视图后获取当前主题和属性。以下是我在DatePickerDialog上编写和测试的一些方法,以查找正在使用的样式:

从上下文中获取当前主题:

static String getThemeNameFromContext(Context context) {
    Resources.Theme theme = context.getTheme();
    String themeName;
    try {
        Field field = theme.getClass().getDeclaredField("mThemeResId");
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        int themeResId = field.getInt(theme);
        themeName = context.getResources().getResourceEntryName(themeResId);
    } catch (Exception e) {
        // If we are here then the context is most likely the application context.
        // The theme for an application context is always "Theme.DeviceDefault"
        themeName = "Theme.DeviceDefault";
    }
    return themeName;
}

获取属性的名称/值:

static String getResourceName(Context context, int attribute) {
    TypedArray typedArray = context.obtainStyledAttributes(new int[]{attribute});
    try {
        int resourceId = typedArray.getResourceId(0, 0);
        return context.getResources().getResourceEntryName(resourceId);
    } finally {
        typedArray.recycle();
    }
}

在下面的示例中,我创建了一个DatePickerDialog,并使用上述方法获得了对话框和对话框的正面按钮使用的主题和属性值:

// Create the DatePickerDialog
DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(),
        new DatePickerDialog.OnDateSetListener() {

            @Override
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {

            }
        }, 2015, Calendar.SEPTEMBER, 9);
// Show the dialog
datePickerDialog.show();

// Get the positive button from the dialog:
Button positiveButton = datePickerDialog.getButton(DatePickerDialog.BUTTON_POSITIVE);
// Get the theme used by this dialog
String theme = getThemeNameFromContext(datePickerDialog.getContext());
// Get the date picker style used by the dialog
String datePickerStyle = getResourceName(datePickerDialog.getContext(), android.R.attr.datePickerStyle);
// Get the style of the positive button:
String buttonStyle = getResourceName(positiveButton.getContext(), android.R.attr.buttonStyle);

Log.i("LOGTAG", "Theme: " + theme);
Log.i("LOGTAG", "datePickerStyle: " + positiveButton);
Log.i("LOGTAG", "buttonStyle: " + buttonStyle);

在我的测试项目中,我获得了themedatePickerStylebuttonStyle的这些值:

  

主题:ThemeOverlay.Material.Dialog

     

datePickerStyle:Widget.Material.Light.DatePicker

     

buttonStyle:Widget.Material.Light.Button

这有点帮助,但我们仍然没有改变正面和负面的按钮风格。如果我们查看source for DatePickerDialog,我们可以看到它扩展了AlertDialog。这会使事情变得更难,因为您需要在主题中设置自定义样式,这会影响所有AlertDialog按钮。如果您需要有关如何更改buttonStyle的示例,请发表评论。

更好的方法是在对话框可见后设置正负按钮的样式。例如,在DialogFragment中,您可以将以下代码放在onStart()中以设置按钮的样式:

@Override
public void onStart() {
    super.onStart();
    DatePickerDialog dialog = (DatePickerDialog) getDialog();
    Button btnPos = dialog.getButton(DatePickerDialog.BUTTON_POSITIVE);
    Button btnNeg = dialog.getButton(DatePickerDialog.BUTTON_NEGATIVE);

    /* customize the buttons here */
    btnPos.setText("CUSTOM");
    btnPos.setTextAppearance(android.R.style.TextAppearance_Large);
    btnNeg.setTextColor(Color.RED);
}

enter image description here

<强>结论:

您可以在其他视图上使用上述方法来查找适用于该视图的样式。 Android上的a **样式小部件仍然很痛苦。您可能需要不时地浏览源代码和XML。