DylanCaiCoding / ViewBindingKTX

The most comprehensive utils of ViewBinding. (最全面的 ViewBinding 工具,支持 Kotlin 和 Java 用法,支持 BRVAH,支持封装到基类,支持 DataBinding,支持选择是否使用反射)
Apache License 2.0
816 stars 92 forks source link

Fragment绑定失败? #54

Closed aheven closed 2 years ago

aheven commented 2 years ago

版本号:2.0.5

Fragment绑定失败?原始代码为:

<!-- activity_main.xml -->
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="**.main.MainFragment"
    android:fitsSystemWindows="true"/>

<!-- MainFragment -->
class MainFragment : Fragment() {
    private val binding:FragmentMainBinding by binding()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.content.text = "123456"
    }
}

但是在页面中,MainFragment的布局无法加载出来。

查看源码,发现并没有将View绑定至Fragment的相关代码:

class FragmentBindingProperty<VB : ViewBinding>(private val clazz: Class<VB>) : ReadOnlyProperty<Fragment, VB> {

  override fun getValue(thisRef: Fragment, property: KProperty<*>): VB =
    requireNotNull(thisRef.view) { "The property of ${property.name} has been destroyed." }
      .getBinding(clazz).also { binding ->
        if (binding is ViewDataBinding) binding.lifecycleOwner = thisRef.viewLifecycleOwner
      }
}

是否和这个有关系?

aheven commented 2 years ago

看到示例,Fragment 构造传递了资源 ID,所以是通过这种方式初始化的。因此 by binding() 的作用仅为绑定 Fragment 视图。 对于 Androidx 低版本,例如,AppCompatDialogFragmentandroidx.appcompat 1.4.0 之前未添加 ResourceId 构造参数,AppCompatActivityandroidx.appcompat 1.1.0 之前未添加 ResourceId 构造参数。

建议添加 View 为空的时候抛出异常提示将 View 添加到 Fragment。

DylanCaiCoding commented 2 years ago

感谢反馈,已将异常提示改为 The constructor missing layout id or the property of ${property.name} has been destroyed.

DialogFragment 是推荐下面这么来用,binding 写在 Dialog 里。

class LoadingDialogFragment(private val text: String? = null) : DialogFragment() {

  override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    isCancelable = false
    return LoadingDialog(requireContext())
  }

  inner class LoadingDialog(context: Context) : Dialog(context, R.style.DialogTheme) {
    private val binding: DialogLoadingBinding by binding()

    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      window?.setLayout(MATCH_PARENT, WRAP_CONTENT)
      binding.tvMessage.text = "Wait a minute..."
    }
  }
}