为啥使用 View Binding 会改变布局?
Posted
技术标签:
【中文标题】为啥使用 View Binding 会改变布局?【英文标题】:Why using View Binding is changing the layout?为什么使用 View Binding 会改变布局? 【发布时间】:2020-08-24 23:47:10 【问题描述】:实际代码:
我的主要活动:
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_height
是wrap_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:gravity
和 android: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 会改变布局?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 binding.myTextView 返回一个 TextView?而不是 TextView