Custom attr get color returns invalid values

If you want every types of color to work

  • hex: #ff0000
  • color resource: @color/primary
  • color selector: @color/primaryWithStates

You need to define your property as both color and reference

<attr name="propertyTextColor" format="color|reference" />

Then you simply access the value using getColorStateList

val colors = attr.getColorStateList(R.styleable.PropertyView_propertyTextColor)
titleTextView.setTextColor(colors)

For advanced needs where you want to digest the ColorStateList yourself

  • In the first 2 cases you can access the color using colors.defaultColor
  • If you used a selector you have to call the method getColorForState

So, the easiest way to extract the color is by doing

val currentColor = colors.getColorForState(drawableState, colors.defaultColor)
// do whatever you want with the color

It returns the color if there is one for the current state, otherwise the default one

Attention: getColorForState should be placed in the drawableStateChanged() method to be notified every time the state changes


The is some sort of bug with attrs.

The following works perfectly.


attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- Your View -->
    <declare-styleable name="YourView">
        <attr name="tint_color" format="reference" /> <!-- Important -->
        <attr name="ripple_drawable" format="reference" /> <!-- Important -->
    </declare-styleable>

</resources>

YourView.java

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

public YourView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
}

public YourView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    // Get attrs
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.YourView, defStyleAttr, 0);

    // Set tint
    int tintStyle = R.styleable.YourView_tint_color;
    if (a.hasValue(tintStyle)) {
        mTintColor = a.getResourceId(tintStyle, 0); // Important
        setTint(mTintColor);
    }

    // Set Ripple
    int rippleStyle = R.styleable.YourView_ripple_drawable;
    if (a.hasValue(rippleStyle)) {
        mRippleDrawable = a.getResourceId(rippleStyle, 0); // Important
        setRipple(mRippleDrawable);
    }

    // End
    a.recycle();
}

Usage

<com.your.app.YourView
    ...
    app:ripple_drawable="@drawable/ripple_default"
    app:tint_color="@color/colorWhite" />

You are using a reference to a color in your example, however according to your attrs.xml file, that property must be of a color type, not a reference. This is probably the reason why when you used a hex color code it worked, but using a reference returned -1.

If you do change the format to a reference, you should also change the method to retrieve it from a.getColor() to a.getColorStateList().