Android:如何在基础 class 中使用视图绑定并从 kotlin synthetics 迁移

Android: How to use viewbinding in base class and migrate from kotlin synthetics

随着 kotlin synthetics 的弃用,我遇到了一个问题,我无法再从我的 base class 访问某些标准布局。例如,我有一个用于三个片段的基础 class,并且在所有片段中,都有一个按钮。我的旧方法是使用合成器在基础 class 中获取按钮,然后分配一些默认的点击监听器等

我的问题是:从合成迁移到此处的视图绑定/数据绑定的最佳方法是什么?我问自己的另一个问题是,我现在如何访问 activity / 片段之外的 view_layouts?

基地class

abstract class BaseRebuildFragment(layout: Int) : Fragment(layout) {
    abstract val nextFragment: NavDirections
    abstract val baseViewModel: ViewModel
    open val dataOverViewFragment: Boolean = false
    @Inject @RebuildProgressDescription lateinit var progressBarDescription: ArrayList<String>

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initAppStandardToolbar()
        initStateProgressBar(progressBarDescription)
        initButton()
        hideBottomNav()
    }

    private fun initButton() {
        calibrate_btn_next.setOnClickListener { // not working anymore
            if (dataOverViewFragment) return@setOnClickListener else if (this.validForm()) findNavController().navigate(nextFragment)
        }
    }

    open fun validForm(): Boolean { return false }
}

片段

@AndroidEntryPoint
class RebuildOptionFragment : BaseRebuildFragment(R.layout.fragment_rebuild_option) {
    override val baseViewModel: RebuildViewModel by navGraphViewModels(R.id.nav_send_rebuild) { defaultViewModelProviderFactory }
    private val rebuildBinding: FragmentRebuildOptionBinding by viewBinding()
    override val nextFragment: NavDirections = RebuildOptionFragmentDirections.actionRebuildOptionFragmentToRebuildUserDataFragment()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        bindObjects()
        baseViewModel.setStateEvent(RebuildStateEvent.GetPrice)
        subscribeRebuildListObserver()
    }

    private fun bindObjects() = with(rebuildBinding) {
        viewModel = baseViewModel
        lifecycleOwner = viewLifecycleOwner
        lendingListener = LendingSwitch()
    }

    override fun validForm(): Boolean = baseViewModel.shippingValidator.isShippingOptionsValid()
}

访问 activity 之外的视图/utils 包中的片段

fun Fragment.initStateProgressBar(progressBarDescription: ArrayList<String>) = with(app_standard_progress_bar) { // not working anymore
    setStateDescriptionData(progressBarDescription)
}

fun Fragment.initAppStandardToolbar() {
    toolbar.setupWithNavController(findNavController(), AppBarConfiguration(findNavController().graph)) // not working anymore
}

findViewById 可以直接使用而不是使用合成来完成同样的事情,但是没有类型安全。您必须提供类型,因为它无法推断类型。

fun Fragment.initStateProgressBar(progressBarDescription: ArrayList<String>) = with(requireView().findViewById<ProgressBar>(R.id.app_standard_progress_bar)) { 
    setStateDescriptionData(progressBarDescription)
}

对于视图绑定,您应该使用生成的绑定 class 自行扩充布局 - 因此对于 R.layout.fragment_rebuild_option,它应该是 FragmentRebuildOptionBinding

onCreateView 中,调用 class 上的 inflate 选项:

binding = FragmentRebuildOptionBinding.inflate(inflater, container, false)
// return the root layout view
return binding.root

这会创建一个绑定对象,它将所有 View 引用作为属性,就像您使用合成物一样 - 所以像 binding.calibrate_btn_next 这样的东西。这意味着 binding 需要成为您的 Fragment class 中的成员变量,因此您的所有函数都可以访问它。

那么基本上只是将所有代码更改为引用 binding.whatever 而不是 whatever

对于在不确定类型安全的情况下访问的动态视图,您可以像往常一样使用 findViewById

要访问片段中的视图,您可以使用requireView()