I'm migrating from kotlinx.android.synthetic to ViewBindings.
I have two layouts(for phones and tablets) with the same set of ids:
class GameActivity: AppCompatActivity() {
lateinit var binding: ViewBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (AppData.instance.isTablet)
binding=ActivityGameTabletBinding.inflate(layoutInflater)
else
binding=ActivityGamePhoneBinding.inflate(layoutInflater)
setContentView(binding.root)
val btn=binding.menuBtn //no such property
}
...
}
The problem is binding contains only one property which is root.
Thus I'm forced to fallback to old getViewById. Is there way to have viewBinding features for different layouts?
You cannot have a variable have binded to 2 different views instead you can create 2 variables and initialize both of them and use them accordingly.
Here is an example.
private lateinit var phoneBinding : ActivityGamePhoneBinding
private lateinit var tabletBinding : ActivityGameTabletBinding
Then initialize both of them.
phoneBinding = ActivityGamePhoneBinding.inflate(layoutInflater)
tabletBinding = ActivityGameTabletBinding.inflate(layoutInflater)
if (AppData.instance.isTablet){
val btn = tabletBinding.button
//Do rest of your tablet code
} else {
val btn = phoneBinding.button
//Do rest of your phone code
}
If you are doing common things you should create a function and call the same function in both scenarios.
phoneBinding = ActivityGamePhoneBinding.inflate(layoutInflater)
tabletBinding = ActivityGameTabletBinding.inflate(layoutInflater)
if (AppData.instance.isTablet){
val btn = tabletBinding.button
onButtonClick(btn)
} else {
val btn = phoneBinding.button
onButtonClick(btn)
}
fun onButtonClick(button : Button){
button.setOnclickListner{
//rest of you code.
}
}
For those who might facing the same problem. I found two solutions:
Method 1: Use kotlin-reflection library to get properties by it's string name:
private inline fun <T>getViewByName(name:String):T{
val prop= binding::class.memberProperties.find { it.name==name }
val view=prop?.call(binding) as T
if (view!=null) {
return view
} else
throw Exception("view not found")
}
I find this method quite hacky, so I sticked to the second one:
class GameActivityBinding(private val binding:ViewBinding) {
val menuBtn:ImageButton
get() {
return when (binding) {
is ActivityGameTabletBinding -> {
binding.menuBtn
}
is ActivityGamePhoneBinding -> {
binding.menuBtn
}
else -> throw Exception("incorrect layout")
}
}
// rest of the views
}
No need to litter code with dozens of if-else's
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With