Kotlin: How to Access Attrs for CustomView

I am creating a custom view in Kotlin and would like to access the Resource attribute.

Below is my code

class CustomCardView : FrameLayout { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) init { LayoutInflater.from(context).inflate(R.layout.view_custom_card, this, true) if (attrs != null) { val a = context.obtainStyledAttributes(attrs, R.styleable.custom_card_view) if (a.hasValue(R.styleable.custom_card_view_command)) { var myString = a.getString(R.styleable.custom_card_view_command) } } } } 

Note that this will be a bug in attrs in the init function. I am wondering how to access attrs ?

+13
source share
4 answers

You cannot access the second constructor parameter from the init block. But there are at least two ways to implement similar functionality.

The first approach uses a single primary constructor with default parameters instead of several secondary constructors. In this case, you must apply the @JvmOverloads annotation to the constructor in order to force Kotlin to generate three different constructors.

 class CustomCardView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout { init { LayoutInflater.from(context).inflate(R.layout.view_custom_card, this, true) if (attrs != null) { val a = context.obtainStyledAttributes(attrs, R.styleable.custom_card_view) if (a.hasValue(R.styleable.custom_card_view_command)) { var myString = a.getString(R.styleable.custom_card_view_command) } } } } 

The seconds approach is two chain constructors and moving the contents of an init block into a constructor with three arguments.

 class CustomCardView : FrameLayout { constructor(context: Context) : this(context, null) constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { LayoutInflater.from(context).inflate(R.layout.view_custom_card, this, true) if (attrs != null) { val a = context.obtainStyledAttributes(attrs, R.styleable.custom_card_view) if (a.hasValue(R.styleable.custom_card_view_command)) { var myString = a.getString(R.styleable.custom_card_view_command) } } } } 
+15
source

Why don't you just skip these detailed constructors with default values ​​and do it like this:

 class CustomCardView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr) { init { inflate(context, R.layout.view_custom_card, this) attrs?.let { val typedArray = context.obtainStyledAttributes(it, R.styleable.custom_card_view) val myString = typedArray.getString(R.styleable.custom_card_view_command) } } 
+2
source

Adapting your code, I think you can also do something like this:

 class CustomCardView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : FrameLayout(context, attrs, defStyleAttr) { constructor(context: Context) : this(context, null) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) init { LayoutInflater.from(context).inflate(R.layout.view_custom_card, this, true) if (attrs != null) { val a = context.obtainStyledAttributes(attrs, R.styleable.custom_card_view) if (a.hasValue(R.styleable.custom_card_view_command)) { var myString = a.getString(R.styleable.custom_card_view_command) } a.recycle() } } } 
0
source

This is a bit verbose, but should work as expected under any conditions:

 import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import android.widget.FrameLayout class CustomCardView: FrameLayout { constructor(context: Context) : super(context) { initialize(context, null) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize(context, attrs) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize(context, attrs) } private fun initialize(context: Context, attrs: AttributeSet?) { LayoutInflater.from(context).inflate(R.layout.view_custom_card, this, true) attrs?.let { val a = context.obtainStyledAttributes(it, R.styleable.custom_card_view) if (a.hasValue(R.styleable.custom_card_view_command)) { var myString = a.getString(R.styleable.custom_card_view_command) } } } } 
0
source

All Articles