SwiftUI - ScrollView 框架的意外行为
SwiftUI - unexpected behavior with the frame of a ScrollView
我在 ScrollView 中使用 ForEach,它有一个框架来确保它的大小正确。
这是我创建的最小工作示例(保留所有修饰符,因为它们可能是相关的):
import SwiftUI
struct FirstView: View {
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
@State var items: [String] = []
var body: some View {
VStack{
HStack{
ScrollView{
Text("Items")
.font(.caption)
ForEach(self.items, id: \.self) { item in
Text(item)
.bold()
.font(.footnote)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(5)
.frame(width: self.screenWidth * 0.27)
.padding(5)
.background(Color(red: 85/255, green: 91/255, blue: 2/255))
.cornerRadius(10)
.foregroundColor(.white)
.padding(4)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(red: 21/255, green: 234/255, blue: 53/255), lineWidth: 3)
)
.padding(4)
}
}
.frame(width: screenWidth * 0.3, height: screenHeight * 0.12)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.black, lineWidth: 2)
)
}
Button(action: {
self.items.append("item")
}){
Text("add item")
}
}
}
}
struct FirstView_Previews: PreviewProvider {
static var previews: some View {
FirstView()
}
}
对于这个示例,我希望 ForEach 循环内的每个项目都与 ScrollView 本身具有相同的宽度。情况就是这样,如果您启动视图时项目 已经在 项目数组中。例如,如果我开始
@State var items: [String] = ["item1", "item2"]
我得到这样的结果:
这正是您所期望的。
如果我按下“添加项目”,项目将按预期添加。
但是 如果我从一个 空 项数组开始(如以下代码所示),然后按 add item 按钮,我们得到这样的东西:
这完全不是预期的。整个项目都在那里,我们甚至可以在 ScrollView 内部水平滚动以查看整个项目,但看起来 ScrollView 的 frame 宽度不正确。
我试过在这里和那里添加一些框架修改器来尝试解决这个问题,但找不到解决方案。
如果有人以前见过这个问题,或者知道问题是什么is/how我可以解决它,将不胜感激。
使用 SwiftUI 2.0 一切正常 as-is
SwiftUI 1.0+
对于空的 ScrollView,他们没有检测到完整的可能宽度(因为动态部分是空的),所以宽度是最大可用 child(在你的情况下是“项目”标题)或默认最小值,如果里面有no-one
解决方案是将动态内容嵌入到某个容器中,并为其提供滚动视图本身的最大可用宽度。
测试 Xcode 11.4 / iOS 13.4
ScrollView{
Text("Items")
.font(.caption)
VStack {
ForEach(self.items, id: \.self) { item in
Text(item)
.bold()
.font(.footnote)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(5)
.frame(maxWidth: .infinity)
.padding(5)
.background(Color(red: 85/255, green: 91/255, blue: 2/255))
.cornerRadius(10)
.foregroundColor(.white)
.padding(4)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(red: 21/255, green: 234/255, blue: 53/255), lineWidth: 3)
)
.padding(4)
}
}
.frame(maxWidth: .infinity)
}
我在 ScrollView 中使用 ForEach,它有一个框架来确保它的大小正确。
这是我创建的最小工作示例(保留所有修饰符,因为它们可能是相关的):
import SwiftUI
struct FirstView: View {
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
@State var items: [String] = []
var body: some View {
VStack{
HStack{
ScrollView{
Text("Items")
.font(.caption)
ForEach(self.items, id: \.self) { item in
Text(item)
.bold()
.font(.footnote)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(5)
.frame(width: self.screenWidth * 0.27)
.padding(5)
.background(Color(red: 85/255, green: 91/255, blue: 2/255))
.cornerRadius(10)
.foregroundColor(.white)
.padding(4)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(red: 21/255, green: 234/255, blue: 53/255), lineWidth: 3)
)
.padding(4)
}
}
.frame(width: screenWidth * 0.3, height: screenHeight * 0.12)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.black, lineWidth: 2)
)
}
Button(action: {
self.items.append("item")
}){
Text("add item")
}
}
}
}
struct FirstView_Previews: PreviewProvider {
static var previews: some View {
FirstView()
}
}
对于这个示例,我希望 ForEach 循环内的每个项目都与 ScrollView 本身具有相同的宽度。情况就是这样,如果您启动视图时项目 已经在 项目数组中。例如,如果我开始
@State var items: [String] = ["item1", "item2"]
我得到这样的结果:
这正是您所期望的。
如果我按下“添加项目”,项目将按预期添加。
但是 如果我从一个 空 项数组开始(如以下代码所示),然后按 add item 按钮,我们得到这样的东西:
这完全不是预期的。整个项目都在那里,我们甚至可以在 ScrollView 内部水平滚动以查看整个项目,但看起来 ScrollView 的 frame 宽度不正确。
我试过在这里和那里添加一些框架修改器来尝试解决这个问题,但找不到解决方案。
如果有人以前见过这个问题,或者知道问题是什么is/how我可以解决它,将不胜感激。
使用 SwiftUI 2.0 一切正常 as-is
SwiftUI 1.0+
对于空的 ScrollView,他们没有检测到完整的可能宽度(因为动态部分是空的),所以宽度是最大可用 child(在你的情况下是“项目”标题)或默认最小值,如果里面有no-one
解决方案是将动态内容嵌入到某个容器中,并为其提供滚动视图本身的最大可用宽度。
测试 Xcode 11.4 / iOS 13.4
ScrollView{
Text("Items")
.font(.caption)
VStack {
ForEach(self.items, id: \.self) { item in
Text(item)
.bold()
.font(.footnote)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(5)
.frame(maxWidth: .infinity)
.padding(5)
.background(Color(red: 85/255, green: 91/255, blue: 2/255))
.cornerRadius(10)
.foregroundColor(.white)
.padding(4)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(red: 21/255, green: 234/255, blue: 53/255), lineWidth: 3)
)
.padding(4)
}
}
.frame(maxWidth: .infinity)
}