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 ]代表。
用法:
class ChildClass: AppCompatDialogFragment(R.layout.child_class_view) {
private val binding by viewBinding(ChildClassViewBinding::bind)
}
目的是声明一个基地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 ]代表。
用法:
class ChildClass: AppCompatDialogFragment(R.layout.child_class_view) {
private val binding by viewBinding(ChildClassViewBinding::bind)
}