具有视图绑定的 BaseFragment

BaseFragment with viewbinding

要在 android 应用程序中使用 viewbinding 我基本上是为 ActivityFragment 创建基础 类 以删除每次编写充气代码的样板.

ACTIVITY:

BaseActivityviewbinding:

abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = getViewBinding()
    }

    abstract fun getViewBinding(): VB

}

MainActivity:

class MainActivity : BaseActivity<ActivityMainBinding>() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        //we can directly use binding now and it works fine inside activity
        //binding.view.doSomething() 
    }

 override fun getViewBinding(): ActivityMainBinding = ActivityMainBinding.inflate(layoutInflater)
}

碎片 :

BaseFragment:

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

    var binding: VB? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = getViewBinding(view)
    }

    abstract fun getViewBinding(view: View): VB
}

DemoFragment:

class DemoFragment : BaseFragment<DemoFragmentBinding>() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //problem is here
        binding.txtData.text="Something"
    }

    override fun getViewBinding(view: View): DemoFragmentBinding = DemoFragmentBinding.bind(view)

}

demo_fragment.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.fragments.DemoFragment">

    <TextView
        android:id="@+id/txt_data"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello" />

</FrameLayout>

Problem : Unable to access views using binding inside Demofragment. I don't know why it works with activity and not with fragment.

2nd way that I don't want todo:

实施'androidx.fragment:fragment-ktx:1.3.1'

class DemoFragment : Fragment(R.layout.demo_fragment) {

    lateinit var binding: DemoFragmentBinding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding = DemoFragmentBinding.bind(view).apply {
            txtData.text = "Hello World"
        }
    }
}

我查看了文档,我不确定这是否会破坏您对 BaseFragment 中抽象模式的要求,但我使用此更改测试了您的代码并且它有效。唯一的变化是 DemoFragment:

//Add this for the onCreateView implementation
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = DemoFragmentBinding.inflate(LayoutInflater.from(context), null, false)
        val view = binding!!.root
        return view
    }

然后我在onViewCreated测试:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //problem is here
        binding?.txtData?.text="Something"

    }

它奏效了。我查看的文档是 this section

我认为这样做仍然可以避免一些样板代码,但是 onCreateView 覆盖对于每个片段都是必需的,因为不同的视图绑定 inflation(例如 DemoFragmentBinding.inflate etc etc)

您需要覆盖 BaseFragment 中的 onCreateView 并初始化视图绑定

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

然后改变这一行

override fun getViewBinding(view: View): DemoFragmentBinding = DemoFragmentBinding.bind(view)

override fun getViewBinding() = DemoFragmentBinding.inflate(layoutInflater)

基础片段:

abstract class BaseFragment<VB : ViewBinding> : Fragment() {
    private var _binding: VB? = null
    val binding get() = _binding!!

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

    abstract fun getViewBinding(): VB
}

DemoFragment:

class DemoFragment : BaseFragment<DemoFragmentBinding>() {

    override fun getViewBinding() = DemoFragmentBinding.inflate(layoutInflater)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.apply {
            txtData.text = "Something"
        }
    }
}

这里是实现此 factory abstraction with ViewBinding. I am sharing the implementation code below. I am using genrics 的另一种方法。如果有人需要进一步解释,我在这里。确保您已经在 build.gradle 文件中启用了 viewbinding 功能。然后使用以下 BaseFragment.kt 作为您的片段抽象。

基础片段:

typealias Inflate<T> = (LayoutInflater, ViewGroup?, Boolean) -> T

abstract class BaseFragment<V: ViewBinding>(
    private val inflate: Inflate<V>
    ) : Fragment() {

    private lateinit var _binding: V
    val binding get() = _binding

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

N:B:了解更多 typealias

主页片段:

// Implement the BaseFragment like below
class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::inflate) {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // usages by calling public variable 'binding' from base class
        binding.message.text = "update $value"
    }
}

使用https://github.com/hoc081098/ViewBindingDelegate

abstract class BaseFragment<VB : ViewBinding>(@LayoutRes layoutId: Int) : Fragment(layoutId) {
  protected abstract val binding: VB
}


import com.hoc081098.viewbindingdelegate.*
class MainFragment: BaseFragment<FragmentMainBinding>(R.layout.fragment_main) {
  override val binding by viewBinding()
}