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

Cri*_*ris 6 android android-styles

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

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

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

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

Jar*_*ler 6

在Android上查找如何更改小部件的样式一直很麻烦.例如,DatePickerDialogHolo和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;
}
Run Code Online (Sandbox Code Playgroud)

获取属性的名称/值:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在下面的示例中,我创建了一个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);
Run Code Online (Sandbox Code Playgroud)

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

主题:ThemeOverlay.Material.Dialog

datePickerStyle:Widget.Material.Light.DatePicker

buttonStyle:Widget.Material.Light.Button


这有点帮助,但我们仍然没有改变正面和负面的按钮样式.如果我们查看源代码,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);
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


结论:

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