Kotlin 在父级中膨胀通用视图绑定 class

Kotlin inflate generic viewbinding class in parent

目的是声明一个基地class

abstract class BaseDialog<T : ViewBinding> : AppCompatDialogFragment() {
       lateinit var binding: T
}

并且所有子 classes 都应该扩展这个父 class

class ChildClass: BaseDialog<ChildClassViewBinding>() {
}

然后我想在父 class 中膨胀绑定并将其保存到绑定 属性 这似乎超出了我对 kotlin 的知识范围

这真的可以吗?

创建基础片段

abstract class BaseFragment<VB : ViewBinding> : Fragment() {

    private var _bi: VB? = null
    protected val bi: VB get() = _bi!!

    abstract val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> VB

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        _bi = bindingInflater(inflater, container, false)
        return _bi!!.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _bi = null
    }
}

在您的子片段中

class HomeFragment : BaseFragment<HomeFragmentBinding>() {
    override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> HomeFragmentBinding
        get() = HomeFragmentBinding::inflate
}

如果我要这样做,我会这样做:

class BaseDialogFragment<T: ViewBinding>(private val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> T)
: AppCompatDialogFragment() {
    var _binding: T? = null
    val binding: T get() = _binding ?: error("Must only access binding while fragment is attached.")

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = bindingInflater(inflater, container, false)
        return binding.root
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

用法如下:

class ChildClass: BaseDialog(ChildClassViewBinding::inflate) {

}

但是,我一开始就不会这样做(因为有一个不错的选择)。依靠继承来处理这些事情很快就会变得一团糟。如果您想为依赖注入框架添加一些其他功能,或者您喜欢使用的其他一些常用功能,会发生什么情况?如果您喜欢在某些片段中使用某些功能而不是全部片段怎么办?你是否也像这样为 Activity 和 non-Dialog 片段创建基础 类?

这些问题就是为什么有一个编程公理:“组合优于继承”。

有时别无选择,只能使用继承来避免代码重复。但就 Fragments 和 Bindings 而言,我不这么认为。您可以将布局引用传递给超级构造函数,并使用 ViewBinding.bind() 而不是 inflate()。由于很少需要在 onViewCreated 函数之外访问绑定,因此通常不需要 属性。

class ChildClass: AppCompatDialogFragment(R.layout.child_class_view) {

    override fun onViewCreated(view: View, bundle: Bundle?) {
        super.onViewCreated(view, bundle)
        val binding = ChildClassViewBinding.bind(view)
        //...
    }

}

如果你确实需要一个 属性,@EpicPandaForce 有一个库可以使它成为一个 one-liner 并在 [=42= 中为你处理销毁时的 leak-avoidance ]代表。

Library here

用法:

class ChildClass: AppCompatDialogFragment(R.layout.child_class_view) {
    private val binding by viewBinding(ChildClassViewBinding::bind)

}