使用样式化

Working with styleable

我想制作一个包含进度视图和按钮的视图。通过视图的 xml 我想添加定义按钮和 porgress 栏样式的字段。

到目前为止我做了什么但没有用:

   <io.**.**.view.ButtonLoading android:id="@+id/b_recover_password"
                                       android:layout_width="wrap_content"
                                       android:gravity="center"
                                       app:styleButton="@style/ButtonGrey"
                                       app:styleProgress="@style/ProgressBar"
                                       app:textButton="@string/recover_password"
                                       android:layout_height="wrap_content"/>

代码:

   a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.ButtonLoading,
            0, 0);

    int buttonId = 0;// R.style.Widget_AppCompat_Button;
    try {
        buttonId = a.getResourceId(R.styleable.ButtonLoading_styleButton, 0);
    } catch (Exception e) {
    }

    button = new Button(getContext(), attrs, buttonId);

    LayoutParams lpButton = createLayoutParams();
    button.setLayoutParams(lpButton);
    color = button.getCurrentTextColor();

    int progressId = 0;// R.style.Widget_AppCompat_ProgressBar;
    try {
        progressId = a.getResourceId(R.styleable.ButtonLoading_styleProgress, 0);
    } catch (Exception e) {
    }

    progressBar = new ProgressBar(getContext(), attrs, progressId);
    LayoutParams lpProgressBar = createLayoutParams();
    lpProgressBar.addRule(RelativeLayout.CENTER_IN_PARENT);
    progressBar.setLayoutParams(lpProgressBar);

    LayoutParams lpRelativeLayout = createLayoutParams();
    setLayoutParams(lpRelativeLayout);

    addView(button);
    addView(progressBar);

    try {
        String value = a.getString(R.styleable.ButtonLoading_textButton);
        button.setText(value);
    } catch (Exception e) {
    }
    a.recycle();

风格化:

   <declare-styleable name="ButtonLoading">
    <attr name="styleButton" format="reference" />
    <attr name="styleProgress" format="reference" />
    <attr name="textButton" format="string" />
</declare-styleable>

有人帮帮我吗?谢谢

问题出在 ButtonProgressBar 的构造函数中。让我们考虑两个构造函数。 (重点是我的。)(Documentation

View(Context context, AttributeSet attrs, int defStyleAttr) [Appropriate for below API 21]

Perform inflation from XML and apply a class-specific base style from a theme attribute. This constructor of View allows subclasses to use their own base style when they are inflating. For example, a Button class's constructor would call this version of the super class constructor and supply R.attr.buttonStyle for defStyleAttr; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes.

View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) [Appropriate for API 21+]

Perform inflation from XML and apply a class-specific base style from a theme attribute or style resource. This constructor of View allows subclasses to use their own base style when they are inflating.

关注最后两个参数。

defStyleAttr int: An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.

defStyleRes int: A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.

这很混乱,因为有些资源 ID 指向资源 ID,但请耐心等待。

您为 buttonIdprogressId 定义的是指向样式 (<style...) 的资源 ID。如上文所述,此样式资源 ID 适用于 ButtonProgressBar 构造函数的 defStyleRes 属性。您正在尝试将这些资源值中的每一个用作指向当前主题中的属性的 id。换句话说,您是说 R.attr.styleButton (styleButton) 是当前主题中的一个属性,它不是当前定义的。要解决此问题,请将主题样式更改为以下内容:

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="styleButton">@style/ButtonGrey</item>
    ...
</style>        

为了使您的工作与 API 21+ 兼容,您可以保留样式和布局文件,并将自定义视图代码更改为如下所示。 (我只显示按钮的代码,但进度条会类似。)您可能想为 API 21+ (styles-v21.xml).

创建一个单独的样式文件
public CustomViewGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.ButtonLoading,
            0, 0);
    int defStyleRes = 0;
    try {
        defStyleRes = a.getResourceId(R.styleable.ButtonLoading_styleButton, 0);
    } catch (Exception e) {
      // do something
    }
    Button button;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        // defStyleRes is only used if defStyleAttr == 0 
        // or can't be found in the current theme.
        button = new Button(getContext(), attrs, defStyleAttr, defStyleRes);
    } else {
        button = new Button(getContext(), attrs, 
                     (defStyleAttr != 0) ? defStyleAttr : R.attr.styleButton);
    }
    try {
        String value = a.getString(R.styleable.ButtonLoading_textButton);
        button.setText(value);
    } catch (Exception e) {
      // do something
    }
    addView(button);
    a.recycle();
}

按钮文本的设置按照您编写的代码进行。样式比较棘手。要使 app:styleButton="@style/ButtonGrey" 像您预期的那样为所有 API 工作,我认为您必须做类似 this.

的事情

希望对您有所帮助。

我的风格是:

    <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:buttonStyle">@style/ButtonAppTheme</item>
    <item name="android:progressBarStyle">@style/ProgressBarBase</item>
</style>

<style name="ProgressBarBase" parent="android:Widget.Holo.Light.ProgressBar">
    <item name="android:textColorTertiary">@color/color_grey</item>
</style>

<style name="ProgressBar" parent="android:Widget.Holo.Light.ProgressBar">
    <item name="android:textColorTertiary">@color/color_black</item>
</style>

问题是您总是使用 "ProgressBarBase" 样式。也就是说,它不是覆盖。