Custom attr get color returns invalid values

2020-06-07 05:15发布

问题:

I have a custom view in which i want to set the color of a textview.

I have

attrs.xml

<declare-styleable name="PropertyView">
    <attr name="propertyTitle" format="string" localization="suggested" />
    <attr name="showTitle" format="boolean" />
    <attr name="propertyTextColor" format="color" />
    <attr name="propertyTextSize" format="dimension" />
</declare-styleable>

I set it in the layout file

<com.something.views.PropertyView
    android:id="@+id/dwf_rAwayTeamTimePenaltyInput"
    style="@style/mw"
    propertyview:propertyTextSize="16sp"
    propertyview:propertyTitle="@string/AwayTeam"
    propertyview:showTitle="true"
    propertyview:propertyTextColor="@color/textLight" />

And in my code I set it

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

    showTitle = a.getBoolean(R.styleable.PropertyView_showTitle, false);
    String title = a.getString(R.styleable.PropertyView_propertyTitle);
    float textSize = a.getDimension(R.styleable.PropertyView_propertyTextSize, -1);
    int color = a.getColor(R.styleable.PropertyView_propertyTextColor, -1);
    textSize = textSize / getResources().getDisplayMetrics().scaledDensity;
    if(BuildConfig.DEBUG) Log.e(getClass().getName(), "Color set to: " + color);

    setShowTitle(showTitle);
    setTitle(title);
    if(textSize >= 0) mTitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
    if(color != -1) mTitleTextView.setTextColor(color);

    a.recycle();

But color keeps returning -1. I also tried to set color to #000 When i do that i get a value of -16777216

I also tried a.getInteger and a.getInt

Anyone experience with this problem or suggestions?

Solution, thanks to Alex Fu

getColor cannot handle references

It is working now with

ColorStateList color = a.getColorStateList(R.styleable.PropertyView_propertyTextColor);
mTitleTextView.setTextColor(color);

回答1:

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().



回答2:

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" />


回答3:

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

The easiest way to extract a 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

This last part should be placed in the drawableStateChanged() method to be notified every time the state changes