【问题标题】:How to use View Binding on custom views如何在自定义视图上使用视图绑定
【发布时间】:2020-06-11 11:14:40
【问题描述】:

View Binding 作为 Android Jetpack 的一部分发布

文档:https://developer.android.com/topic/libraries/view-binding

我的问题是,如何将视图绑定与自定义视图一起使用。 Google 文档只有展示的 Activity 和 Fragment。

我试过了,但什么也没显示。

LayoutInflater inflater = LayoutInflater.from(getContext());

然后,我使用了这个,但又一次,没有运气。

LayoutInflater inflater = (LayoutInflater)
            getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

我想也许我没有针对我的视图选择正确的布局充气器,但不确定。

【问题讨论】:

标签: android android-custom-view android-viewbinding


【解决方案1】:

只需通知根,以及是否要附加到它

init { // inflate binding and add as view
    binding = ResultProfileBinding.inflate(LayoutInflater.from(context), this)
}

【讨论】:

  • 如何从现有布局资源中扩展视图?喜欢init { inflate(context, R.layout.my_view, this) }
  • ResultProfileBinding 正在引用布局资源。在你的情况下,它将是MyViewBinding.inflate(....)
  • 我是否应该在某处将binding 变量设置为null,类似于they should be implemented in fragments
  • 我们需要在某处将引用设置为 null 吗?
  • 太棒了!不要忘记在 onDetachedFromWindow() 中将绑定设置为 null
【解决方案2】:

您可以立即初始化视图绑定属性

private val binding = CustomViewBinding.inflate(LayoutInflater.from(context), this)

【讨论】:

  • 可以偷懒吗?
  • 你可以,但我认为除非你正在做一个沉重的绑定,否则你不应该让它变得懒惰,因为它会带来额外的开销
  • 如果你的 CustomView 有一个 ConstraintLayout 作为根,你就不能
【解决方案3】:

这是我能想到的最简单的 kotlin 答案。它是一个自定义视图,只包装了一个 TextView,并提供了一个 update(s:String) 函数来更新文本。

<!-- view_stub.xml -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView android:id="@+id/myTextView" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
</layout>

// StubView.kt
class StubView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : FrameLayout(context,attrs,defStyleAttr) {

    val binding = ViewStubBinding.inflate(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
            .also { addView(it.root) }

    fun update(updatedText: String) {
        binding.myTextView.text = updatedText
    }
}

我喜欢这个答案的两点是:

  1. bindingval 而不是 var。我尽量限制vars的数量。
  2. addViewval binding 密切相关,使用 also {} 范围函数而不是 init {} 子句,使 View 的实例化感觉更具声明性。

有人可能会争辩说addView() 确实是一种副作用,应该在init {} 部分中,以便它与binding val 的声明分开。我会反对——声明一个val,然后将它提供给需要它的代码段,这对我来说并不像副作用。

【讨论】:

  • 为什么不简单地将attachToParent=true 放在inflate() 上?应该是等价的。
【解决方案4】:

要使用视图绑定,你需要使用生成的绑定类而不是LayoutInflater,例如,如果布局名称是result_profile.xml,那么你需要使用ResultProfileBinding作为:

class CustomView @kotlin.jvm.JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    private lateinit var binding: ResultProfileBinding

    init { // inflate binding and add as view
        binding = ResultProfileBinding.inflate(LayoutInflater.from(context))
        addView(binding.root)
    }

}
  1. 自动生成的类:result_profile.xml -> ResultProfileBinding(布局名称,附加Binding
  2. 给绑定充气

    ResultProfileBinding.inflate(LayoutInflater.from(context))
    
  3. 使用addView 将层次结构中的视图添加为:

    addView(binding.root)
    

注意:如果您是从ConstraintLayout(是父类)扩展而来,那么使用constraint set

【讨论】:

  • 谢谢。您的回答在某些方面可能会有所帮助,但我需要一种方法来使用视图绑定来膨胀根视图而不是将视图添加到根视图。
  • @EmiRaz 如果您的自定义视图已创建(java/kotlin)然后在 XML 布局中添加您的自定义视图,然后可以直接从 binding 对象以binding.customview 访问您的自定义视图,或者如果您想像听起来那样使用视图绑定(how to use view binding with custom views),然后按照答案进行操作。 仅供参考inflater 用于使用 xml 布局扩展新视图
  • 如果您在 init 块中膨胀视图本身(正如@Emiraz 所要求的),您最终会陷入无限循环,膨胀再次调用 init 块。他在问如何在CustomView 中使用CustomViewBinding
  • @Downvoter:我可以知道拒绝投票的原因吗?因为我已经清楚地添加了有关如何将自定义视图与视图绑定一起使用的详细信息,并在 cmets 的 OP 中添加了缺少的详细信息
  • @JasonToms 为什么会创建一个循环,你测试过吗?因为我们将在自定义视图中使用生成的布局绑定类
【解决方案5】:

如果您尝试将视图绑定与根视图一起使用,这对我有用:

class CustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {

    private lateinit var binding: CustomViewBinding

    override fun onFinishInflate() {
        super.onFinishInflate()
        binding = CustomViewBinding.bind(this)
    }
}

【讨论】:

  • 恐怕您还有其他情况,因为它不能按照您建议的方式工作并且会在 NPE 中崩溃,因为在此自定义视图布局中不会为 id 生成任何内容。
  • 这会泄漏内存吗?在片段中,取消引用onDestory中的绑定很重要
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多