Search code examples
androidkotlinandroid-custom-viewandroid-styles

How to make a custom view fall back to a theme when attr is not found?


so I made a custom view which can be customized with attributes, and that's fine and working. I'm having trouble now implementing a theme system for it though. How can I retrive it?

This is how I initialize the class:

class PairingCard @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr)

and this is were I retrive the attributes:

context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.pairingCard,
            defStyleAttr, R.style.Widget_ScitalysComponents_PairingCard
        ).apply {
            try {
                _strokeColor = getColor(
                    R.styleable.pairingCard_strokeColor,
                    ColorUtils.setAlphaComponent(
                        context.getColorFromAttr(R.attr.colorOnSurface),
                        196
                    )
                )

As you can see now when it doesn't find an attr set up it falls back to a color surface with 196 alpha. How can I make it fall back to the color defined in R.style.Widget_ScitalysComponents_PairingCard?

I have thought of doing another getColor on that, but it doesn't feel right to be honest.

This is attrs.xml:

<declare-styleable name="pairingCard">
    <attr name="strokeColor" format="color|reference"/>
    <attr name="strokeWidth" format="dimension"/>
    <attr name="cardElevation" format="dimension"/>
    <attr name="collapsedBackgroundColor" format="color"/>
    <attr name="expandedBackgroundColor" format="color"/>
    <attr name="chevronTint" format="color"/>
</declare-styleable>

And this is styles.xml:

<style name="Widget.ScitalysComponents.PairingCard" parent="Widget.MaterialComponents.CardView">
    <item name="strokeColor">?attr/colorOnSurface</item>
    <item name="strokeWidth">1dp</item>
    <item name="cardElevation">@dimen/cardview_default_elevation</item>
    <item name="collapsedBackgroundColor">?attr/colorOnSurface</item>
    <item name="expandedBackgroundColor">?attr/colorOnSurface</item>
    <item name="chevronTint">?attr/colorPrimary</item>
</style>

Thanks to everyone!


Solution

  • In your attires.xml you should define a theme reference attribute

    <declare-styleable name="AppTheme">
         <attr name = "pairingCardStyle" format = "reference"/>
    </declare-styleable>
    

    Then you should define attributes in your style

    <style name="Widget.AppTheme.pairingCard" parent="">
         <item name="strokeColor">?attr/colorOnSurface</item>
         .....
    </style>
    

    After then, you have to direct this style to a reference in your theme.

    <style name="Theme.App" parent="Theme.MaterialComponents.DayNight.NoActionBar">
         <item name = "pairingCardStyle">@style/Widget.AppTheme.pairingCard</item>
         ......
    </style>
    

    In your custom view's class, you need to define these attributes

    context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.pairingCard,
            R.attr.pairingCardStyle,
            R.style.Widget_AppTheme_pairingCard
        )