Android 自定义视图中的样式在超级构造函数调用时不受影响

Android 自定义视图中的样式在超级构造函数调用时不受影响,android,android-custom-view,Android,Android Custom View,我正在尝试创建自定义视图,并通过编程设置其样式。我基于AppCompatButton创建了自定义视图: public class RangeSelectorButton extends androidx.appcompat.widget.AppCompatButton { public int onClickKey = -1; public RangeSelectorButton(Context context) { this(context, null);

我正在尝试创建自定义视图,并通过编程设置其样式。我基于AppCompatButton创建了自定义视图:

public class RangeSelectorButton extends androidx.appcompat.widget.AppCompatButton {
    public int onClickKey = -1;

    public RangeSelectorButton(Context context) {
        this(context, null);
    }

    public RangeSelectorButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public RangeSelectorButton(Context context, AttributeSet attrs) {
        this(context, attrs, R.style.RangeSelectorButton);
    }
}
现在我陷入了奇怪的行为中:

<ru.SomeDomain.CustomViews.RangeSelector
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="true" android:focusable="true">

                <!-- In this case all works fine -->
                <ru.SomeDomain.RangeSelectorButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:minHeight="10dp"
                    android:minWidth="40dp"
                    style="@style/RangeSelectorButton"
                    />

                <!-- Style not applies -->
                <ru.SomeDomain.CustomViews.RangeSelectorButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:minHeight="10dp"
                    android:minWidth="40dp"
                    />
</ru.SomeDomain.CustomViews.RangeSelector>

如果我不想每次创建自定义视图时都在xml中使用style属性,该怎么办

如有必要,my style.xml包含:

<style name="RangeSelectorButton" parent="@android:style/Widget.Button">
    <item name="android:background">@drawable/range_toggle_button_selector</item>
</style>

@可拖动/范围切换按钮选择器
范围切换按钮选择器.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/range_unselected" android:state_pressed="false" />
    <item android:drawable="@drawable/range_selected" android:state_pressed="true" />
</selector>

这里的问题是,您正在传递一个样式来代替
defstylettr
参数,该参数需要一个属性,而不是样式。这里有两种解决方案:

  • 使用属性。在
    attrs.xml
    中声明:

    
    
    在应用程序主题中:

    @style/RangeSelectorButton
    
    并将构造函数更改为:

    public RangeSelectorButton(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.rangeSelectorButtonStyle);
    }
    
    例如,如果您正在制作一个库,这是最好的方法,因为它允许用户自定义您的小部件样式

  • 如果不想使用属性,可以调用第四个视图构造函数,该构造函数的参数采用默认样式,而不是属性:

    View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    
    将此构造函数添加到视图中,然后在第二个构造函数中,按如下方式调用第四个构造函数:

    public RangeSelectorButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0, R.style.RangeSelectorButton);
    }
    
    注意,第四个构造函数需要API 21


  • 这里的问题是,您正在传递一个样式来代替
    defstylettr
    参数,该参数需要一个属性,而不是样式。这里有两种解决方案:

  • 使用属性。在
    attrs.xml
    中声明:

    
    
    在应用程序主题中:

    @style/RangeSelectorButton
    
    并将构造函数更改为:

    public RangeSelectorButton(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.rangeSelectorButtonStyle);
    }
    
    例如,如果您正在制作一个库,这是最好的方法,因为它允许用户自定义您的小部件样式

  • 如果不想使用属性,可以调用第四个视图构造函数,该构造函数的参数采用默认样式,而不是属性:

    View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    
    将此构造函数添加到视图中,然后在第二个构造函数中,按如下方式调用第四个构造函数:

    public RangeSelectorButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0, R.style.RangeSelectorButton);
    }
    
    注意,第四个构造函数需要API 21


  • 第二种方法仅适用于直接从视图派生的自定义视图?父视图也必须有第四个构造函数,否则您将无法使用它。第二种方法仅适用于直接从视图派生的自定义视图?父视图也必须有第四个构造函数,否则您将无法使用它。