Why using View Binding is changing the layout?

Viewed 1736

Actual Code:

My Main Activity:

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)

        val rollButton = binding.rollButton
        rollButton.setOnClickListener { rollDice() }

        setContentView(binding.root)
    }

    private fun rollDice() {
        val randomDiceRoll = Random.nextInt(6) + 1
        Toast.makeText(this, randomDiceRoll.toString(), Toast.LENGTH_SHORT).show()
        binding.resultText.text = randomDiceRoll.toString()
    }

My XML file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/result_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="@string/count"
        android:textSize="30sp" />

    <Button
        android:id="@+id/roll_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="@string/roll" />

</LinearLayout>

Preview in android studio:

Preview

Actual layout in device:

actual layout

If I change setContentView(binding.root) to setContentView(R.layout.activity_main), the layout of Android Studio and the device become the same, but of course, the button doesn't work anymore...

Why does this happen? Why is ActivityMainBinding.inflate(layoutInflater) changing the layout? How to fix this?

Thanks

GitHub Repo: https://github.com/Wizard28082006/Dice_Roller

5 Answers

If I change setContentView(binding.root) to setContentView(R.layout.activity_main), the layout of Android Studio and the device become the same

Most likely caused by how the container is not passed to the inflater if the view is inflated like this.

You could try the following instead:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"

And

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        binding = ActivityMainBinding.bind(findViewById(R.id.root))

        val rollButton = binding.rollButton
        rollButton.setOnClickListener { rollDice() }

Maybe you should set android:layout_height as match_parent in your linearlayout and align inner views in it.

There is a difference between android:gravity and android:layout_gravity:

  • android:gravity sets the gravity of the View Content (or child in case it was applied on a ViewGroup).
  • meanwhile android:layout_gravity sets the gravity of the View it is applied on, relative to its parent.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center_vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"
        android:layout_gravity="center_horizontal"
        android:textSize="30sp"/>
</LinearLayout>

Since the screenshots suggest that the question comes from the Udacity course on Andorid, there is a good explanation on the course knowledge hub (link accessible only to the course users). In short, the explanation is the two things mentioned in the setContentView docs and the ViewBinding docs.

First is that when using setContentView the

layout parameters of the specified view are ignored

and the drawback of ViewBinding is

it doesn't support layout variables or layout expressions, so it can't be used to declare dynamic UI content straight from XML layout files

Adding android:gravity = "center" to LinearLayout solves the problem.

Related