为啥使用 View Binding 会改变布局?

Posted

技术标签:

【中文标题】为啥使用 View Binding 会改变布局?【英文标题】:Why using View Binding is changing the layout?为什么使用 View Binding 会改变布局? 【发布时间】:2020-10-02 13:01:05 【问题描述】:

实际代码:

我的主要活动:

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_
    android:layout_
    android:layout_gravity="center_vertical"
    android:orientation="vertical"
    tools:context=".MainActivity">

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

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

</LinearLayout>

在 android studio 中预览:

设备中的实际布局:

如果我把setContentView(binding.root)改成setContentView(R.layout.activity_main),Android Studio和设备的布局就一样了,当然,按钮也不起作用了……

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

谢谢

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

【问题讨论】:

您是否将给定的 xml-Layout 用于数据绑定和普通布局膨胀? @sebi0920 是的,我对两者都使用了相同的 xml 布局。 这是因为你的layout_heightwrap_content 而不是match_parent @EpicPandaForce 但是Android Studio中的预览显示是居中的? 那是因为预览用一个居中的容器包裹了你的视图,但你的视图本身没有居中。 【参考方案1】:

如果我将 setContentView(binding.root) 更改为 setContentView(R.layout.activity_main),Android Studio 和设备的布局将变得相同

如果视图像这样膨胀,很可能是由于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() 

【讨论】:

你能解释一下为什么茎没有通过吗? 嗯,它从来没有通过,是吗?要找到它,你必须这样做 findViewById(Window.ID_CONTENT 但没有人真正这样做。 我花了 6 个小时试图弄清楚 ActivityMainBinding.bind(findViewById(R.id.root)),我真的希望我能给你更多的积分 - 谢谢! @Nefariis 回想起来,使用ActivityMainBinding.bind(findViewById(Window.ID_CONTENT).getChildAt(0))) 在技术上更正确,主要是因为这样您不需要为根容器提供 ID。我一直在调用 container 而不是 root 以停止与 binding.getRoot() 发生冲突。 这不会违背使用视图绑定的目的【参考方案2】:

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

【讨论】:

我从你说我做的改变中得到了一个working code,这个在 android studio 和我的设备上看起来是一样的......但我使用了android:gravity="center_vertical" 而不是 `android:layout_gravity= "center_vertical" 让它工作......你能解释一下为什么会这样吗?【参考方案3】:

android:gravityandroid:layout_gravity 有区别:

android:gravity 设置查看内容(或子元素,如果它应用于ViewGroup)。 同时android:layout_gravity 设置它所应用的视图的重力,相对于其父级
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:orientation="vertical"
    android:gravity="center_vertical"
    tools:context=".MainActivity">

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

【讨论】:

【参考方案4】:

由于截图表明问题来自the Udacity course on Andorid,course knowledge hub 上有很好的解释(链接仅供课程用户访问)。总之,解释就是the setContentView docs和the ViewBinding docs中提到的两件事。

首先是当使用setContentView

指定视图的布局参数被忽略

ViewBinding的缺点是

它不支持布局变量或布局表达式,所以它不能 用于直接从 XML 布局文件声明动态 UI 内容

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于为啥使用 View Binding 会改变布局?的主要内容,如果未能解决你的问题,请参考以下文章

Android View Binding的使用

Android View Binding使用详解

为啥 binding.myTextView 返回一个 TextView?而不是 TextView

再见findViewById之View Binding

Android-Studio中View-Binding的使用

为啥UIView动画会改变View frame?