Kotlin:如何访问自定义视图的属性?

25

我在Kotlin中创建了一个自定义视图,并想要访问它的属性资源。

下面是我的代码:

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)
            }
        }
    }
}

请注意,在init函数中的attrs会出现错误。我想知道如何访问attrs

5个回答

23

你不能从 init 块中访问次要构造函数的参数。但是,有至少两种方式可以实现类似的功能。

第一种方法是使用带有默认参数的单个主构造函数,而不是多个次要构造函数。在这种情况下,您需要对构造函数应用 @JvmOverloads 注释,以使 Kotlin 生成三个不同的构造函数。

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)
      }
    }
  }
}

第二种方法是使用两个链式构造函数,并将 init 块内容移到带有三个参数的构造函数中。

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)
      }
    }
  }
}

1
谢谢!我在思考如何通过默认的init()构造函数进行访问。 - Elye
你也可以使用 let?.{} 语句, attrs?.let { initAttrs(context, it) } - Yvgen
2
使用完毕后应该使用*a.recycle()*。 - DoruAdryan

7

1
使用 val myString 会更好。 - Kiwi Lin

6

为什么不直接跳过这些带有默认值的冗长构造函数,像这样做:

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)
    }
}

由于超类(FrameLayout)的每个构造函数都只是递归调用具有4个参数的构造函数,因此在这里这样做是安全的。 - mlthlschr

1
适应您的代码,我认为您也可以像这样做:
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()
        }
    }
}

1
这段话有点啰嗦,但应该在所有情况下都能按预期工作:
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)
            }
        }
    }
}

获取值后添加行回收。 - Abhishek Garg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接