Author: Petrus Nguyễn Thái Học
- Simplify usage of Android View Binding with Kotlin Property Delegates and solve behavior of Fragment’s ViewLifecycleOwner.
- Simple one-liner ViewBinding in Fragments and Activities with Kotlin.
- Lightweight and simple library.
Liked some of my work? Buy me a coffee (or more likely a beer)
Read ViewBinding Delegate — one line to get details about implementation.
Add it in your root build.gradle at the end of repositories:
- Kotlin
allprojects {
repositories {
...
maven(url = "https://jitpack.io")
}
}
- Groovy
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation("com.github.hoc081098:ViewBindingDelegate:1.4.0")
}
https://developer.android.com/topic/libraries/view-binding#setup
import com.hoc081098.viewbindingdelegate.*
1. Activity (with reflection). See example
Click to expand
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private val viewBinding by viewBinding<ActivityMainBinding>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding.button.setOnClickListener {
startActivity(Intent(this@MainActivity, SecondActivity::class.java))
}
}
}
2. Activity (without reflection): Pass ::bind
method reference. See example
Click to expand
class SecondActivity : AppCompatActivity(R.layout.activity_second) {
private val binding by viewBinding(ActivitySecondBinding::bind)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.root
}
}
3. Fragment (with reflection). See example
Click to expand
class FirstFragment : Fragment(R.layout.fragment_first) {
private val binding by viewBinding<FragmentFirstBinding> {
button.setOnClickListener(null)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.button.setOnClickListener {
findNavController().navigate(R.id.actionFirstFragmentToSecondFragment)
}
}
}
4. Fragment (without reflection): Pass ::bind
method reference. See example
Click to expand
class SecondFragment : Fragment(R.layout.fragment_second) {
private val binding by viewBinding(FragmentSecondBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.root
}
}
5. Includes <merge/>
tag layout: Create 2 ViewBinding
property. See example
Click to expand
class ThirdFragment : Fragment(R.layout.fragment_third) {
private val includeBinding by viewBinding<FragmentThirdIncludeBinding>()
private val binding by viewBinding<FragmentThirdBinding> { buttonThird.setOnClickListener(null) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
includeBinding.textViewThirdInclude.text = "Working..."
binding.buttonThird.setOnClickListener {
Toast.makeText(requireContext(), "Clicked", Toast.LENGTH_SHORT).show()
}
}
}
6. The Dialog
of DialogFragment
See example
Extends DefaultViewBindingDialogFragment
or implements ViewBindingDialogFragment
.
Click to expand
class DemoDialogFragment : DefaultViewBindingDialogFragment() {
private val viewBinding by dialogFragmentViewBinding(R.id.root, DialogFragmentDemoBinding::bind)
private val viewBinding2 by dialogFragmentViewBinding<DialogFragmentDemoBinding>(R.id.root)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AlertDialog.Builder(requireContext())
.setTitle("Demo dialog")
.setNegativeButton("Cancel") { _, _ -> }
.setPositiveButton("OK") { _, _ -> }
.setView(R.layout.dialog_fragment_demo)
.create()
}
override fun onResume() {
super.onResume()
viewBinding.textInputLayout
viewBinding2.textInputLayout
}
}
7. inflateViewBinding
extension methods on ViewGroup
/LayoutInflater
/Context
. See example
Can be used in RecyclerView.Adapter # onCreateViewHolder
to easily create a RecyclerView.ViewHolder
with a ViewBinding
.
Click to expand
import com.hoc081098.viewbindingdelegate.inflateViewBinding
class DemoAdapter : ListAdapter<String, DemoAdapter.VH>(...) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = VH(parent inflateViewBinding false)
override fun onBindViewHolder(holder: VH, position: Int) = holder.bind(getItem(position))
class VH(private val binding: ItemRecyclerBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: String) { ... }
}
}
Must setContentView
before access ViewBinding
property. This can be done easily with constructor
:
public AppCompatActivity(@LayoutRes int contentLayoutId) { ... }
class MainActivity : AppCompatActivity(R.layout.activity_main) { ... }
Fragment
's View
must be not null before access ViewBinding
property. This can be done easily with constructor
:
public Fragment(@LayoutRes int contentLayoutId) { ... }
class FirstFragment : Fragment(R.layout.fragment_first) { ... }
If there is any problem with Proguard
, add below to your app/proguard-rules.pro
:
# ViewBindingDelegate uses Reflection.
-keepclassmembers class ** implements androidx.viewbinding.ViewBinding {
public static ** bind(android.view.View);
public static ** inflate(android.view.LayoutInflater, android.view.ViewGroup, boolean);
public static ** inflate(android.view.LayoutInflater, android.view.ViewGroup);
}
4. Throws IllegalStateException
: "Attempt to get view binding when fragment view is destroyed" when accessing delegate property in onDestroyView
Since version 1.0.0-alpha03 - Feb 16, 2021
, we cannot access ViewBinding delegate property in onDestroyView
(this causes many problems). Recommended way is passing a lambda to onDestroyView: (T.() -> Unit)? = null
parameter of extension functions, eg.
- private val binding by viewBinding<FragmentFirstBinding>()
+ private val binding by viewBinding<FragmentFirstBinding> { /*this: FragmentFirstBinding*/
+ button.setOnClickListener(null)
+ recyclerView.adapter = null
+ }
override fun onDestroyView() {
super.onDestroyView()
- binding.button.setOnClickListener(null)
- binding.recyclerView.adapter = null
}
Since version 1.2.0
, minSdkVersion
has been changed to 14
.
MIT License
Copyright (c) 2020-2022 Petrus Nguyễn Thái Học