为什么使用 View Binding 会改变布局?

Why using View Binding is changing the layout?

实际代码:

我的主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()
    }

我的 XML 文件:

<?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>

在 android 工作室中预览:

设备中的实际布局:

如果我将 setContentView(binding.root) 更改为 setContentView(R.layout.activity_main),Android Studio 和设备的布局将变得相同,但是当然,按钮不再起作用...

为什么会这样?为什么 ActivityMainBinding.inflate(layoutInflater) 改变布局?如何解决这个问题?

谢谢

GitHub 回购: https://github.com/Wizard28082006/Dice_Roller

也许您应该在线性布局中将 android:layout_height 设置为 match_parent 并在其中对齐内部视图。

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

很可能是由于视图像这样膨胀时 container 没有传递给膨胀器造成的。

您可以尝试以下方法:

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

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() }

由于截图表明问题来自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

首先是当使用 setContentView

layout parameters of the specified view are ignored

ViewBinding的缺点是

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

android:gravityandroid:layout_gravity有区别:

  • android:gravity 设置 View Content 的引力(或 child,以防应用于 ViewGroup)。
  • 同时 android:layout_gravity 设置应用它的 View 的重力,相对于其父级
<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>

在 LinearLayout 添加 android:gravity = "center" 解决问题。