自定义视图中的样式不受超级构造函数调用的影响
Style in custom view not affected on super constructor call
我正在尝试创建自定义视图并以编程方式设置其样式。我基于 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属性怎么办?
如果有必要,我的 style.xml 包含:
<style name="RangeSelectorButton" parent="@android:style/Widget.Button">
<item name="android:background">@drawable/range_toggle_button_selector</item>
</style>
range_toggle_button_selector.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>
这里的问题是您在 defStyleAttr
参数的位置传递了一个样式,它需要一个属性,而不是一个样式。这里有两个解决方案:
使用属性。在 attrs.xml
声明:
<attr name="rangeSelectorButtonStyle" format="reference"/>
在您的应用主题中:
<item name="rangeSelectorButtonStyle">@style/RangeSelectorButton</style>
并将构造函数更改为:
public RangeSelectorButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.rangeSelectorButtonStyle);
}
例如,如果您要创建一个库,这是最好的方法,因为它允许用户自定义您的小部件样式。
如果你不想使用属性,你可以调用第四个View构造函数,它有一个参数采用默认样式而不是属性:
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
将此构造函数添加到您的视图中,并在第二个构造函数中调用第四个,如下所示:
public RangeSelectorButton(Context context, AttributeSet attrs) {
this(context, attrs, 0, R.style.RangeSelectorButton);
}
注意第四个构造函数需要API21.
我正在尝试创建自定义视图并以编程方式设置其样式。我基于 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属性怎么办?
如果有必要,我的 style.xml 包含:
<style name="RangeSelectorButton" parent="@android:style/Widget.Button">
<item name="android:background">@drawable/range_toggle_button_selector</item>
</style>
range_toggle_button_selector.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>
这里的问题是您在 defStyleAttr
参数的位置传递了一个样式,它需要一个属性,而不是一个样式。这里有两个解决方案:
使用属性。在
attrs.xml
声明:<attr name="rangeSelectorButtonStyle" format="reference"/>
在您的应用主题中:
<item name="rangeSelectorButtonStyle">@style/RangeSelectorButton</style>
并将构造函数更改为:
public RangeSelectorButton(Context context, AttributeSet attrs) { this(context, attrs, R.attr.rangeSelectorButtonStyle); }
例如,如果您要创建一个库,这是最好的方法,因为它允许用户自定义您的小部件样式。
如果你不想使用属性,你可以调用第四个View构造函数,它有一个参数采用默认样式而不是属性:
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
将此构造函数添加到您的视图中,并在第二个构造函数中调用第四个,如下所示:
public RangeSelectorButton(Context context, AttributeSet attrs) { this(context, attrs, 0, R.style.RangeSelectorButton); }
注意第四个构造函数需要API21.