Reputation: 859
I'm trying to create custom view and set its style programatically. I created custom view based on 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);
}
}
and now I get stuck in strange behaviour:
<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>
What I should to do if I don't want use style attribute in xml every time when I create my custom view?
If it is necessary my style.xml contains:
<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>
Upvotes: 1
Views: 312
Reputation: 7121
The problem here is that you're passing a style in the place of the defStyleAttr
parameter, which expects an attribute, not a style. There's two solutions here:
Use an attribute. In attrs.xml
declare:
<attr name="rangeSelectorButtonStyle" format="reference"/>
and in your app theme:
<item name="rangeSelectorButtonStyle">@style/RangeSelectorButton</style>
and change your constructor to:
public RangeSelectorButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.rangeSelectorButtonStyle);
}
If you're making a library for example, this is the best way of doing it since it allows users to customize your widget style.
If you don't want to use an attribute, you can call the fourth View constructor, which has a parameter that takes a default style and not an attribute:
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
Add this constructor to your view and in the second constructor, call the fourth like this:
public RangeSelectorButton(Context context, AttributeSet attrs) {
this(context, attrs, 0, R.style.RangeSelectorButton);
}
Note that the fourth constructor requires API 21.
Upvotes: 4