Reputation: 695
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?
Upvotes: 3
Views: 76
Reputation: 695
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
Upvotes: 1
Reputation: 644
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.
}
}
Upvotes: 1