获取并设置多个SwiftUI视图之间的最大宽度
Xcode 12.3 | SwiftUI 2.0 | Swift 5.3 我有多个获取并设置多个SwiftUI视图之间的最大宽度,swift,xcode,swiftui,Swift,Xcode,Swiftui,Xcode 12.3 | SwiftUI 2.0 | Swift 5.3 我有多个HStack,它们的第一个元素必须具有相同的宽度,但我不知道如何实现这一点 HStack { Text("Label 1:") Text("Random texts") } 这将显示以下内容: Label 1: Random Texts Label 2 Other Size: Random Texts Additional Text Lab
HStack
,它们的第一个元素必须具有相同的宽度,但我不知道如何实现这一点
HStack {
Text("Label 1:")
Text("Random texts")
}
这将显示以下内容:
Label 1: Random Texts
Label 2 Other Size: Random Texts Additional Text
Label 3 Other Larger Size: Random Texts
我想在不使用vstack
的情况下显示此,因为每个HStack
都是一个列表行
:
Label 1: Random Texts
Label 2 Other Size: Random Texts Additional Text
Label 3 Other Larger Size: Random Texts
[__________________________] [_____________...
same size
我尝试使用一个@propertyWrapper
来存储每个标签背景的GeometryProxy
,并计算最大WrappedValue
,以设置每个标签的.frame(maxWidth:value)
,但如果不成功,我无法使用该属性wrapper(我遇到循环和崩溃)
可以使用标准变量(而不是@State变量)将GeometryReader宽度传递到任何子视图中
试试这段代码,它使用GeometryReader和一个可识别项列表,这些项被传递一个“labelWidth”,它们为所有标签呈现相同的宽度。注意:我在行中使用了VStack,因此它看起来更好,不明白为什么行中不能有VStack
[![struct Item : Identifiable {
var id:UUID = UUID()
var label:String
var val:\[String\]
}
struct ItemRow: View {
var labelWidth:CGFloat = 0
var item:Item
var body: some View {
HStack(spacing:5) {
Text(item.label)
.frame(width:labelWidth, alignment: .leading)
VStack(alignment: .leading) {
ForEach(0 ..< item.val.indices.count) { idx in
Text(item.val\[idx\])
}
}
}
}
}
struct ContentView : View {
@State var items:\[Item\] = \[
Item(label:"Label 1:", val:\["Random texts"\]),
Item(label:"Label 2 Other Size:", val:\["Random texts","Additional text"\]),
Item(label:"Label 3 Other Larger Size:", val:\["Random texts", "Random texts and texts", "Random texts", "Random texts"\])
\]
var body: some View {
GeometryReader { geo in
let labelWidth = geo.size.width * 0.6 // set this however you want to calculate label width
List(items) { item in
ItemRow(labelWidth: labelWidth, item: item)
}
}
}
}][1]][1]
[![struct Item:可识别{
变量id:UUID=UUID()
变量标签:字符串
var val:\[String\]
}
struct ItemRow:视图{
变量标签宽度:CGFloat=0
var项目:项目
var body:一些观点{
HStack(间距:5){
文本(项目标签)
.frame(宽度:labelWidth,对齐:。前导)
VStack(对齐:。前导){
ForEach(0..
您可以使用标准变量(而不是@State变量)将GeometryReader宽度传递到任何子视图中
试试这段代码,它使用GeometryReader和一个可识别项列表,这些项被传递一个“labelWidth”,它们为所有标签呈现相同的宽度。注意:我在行中使用了VStack,因此它看起来更好,不明白为什么行中不能有VStack
[![struct Item : Identifiable {
var id:UUID = UUID()
var label:String
var val:\[String\]
}
struct ItemRow: View {
var labelWidth:CGFloat = 0
var item:Item
var body: some View {
HStack(spacing:5) {
Text(item.label)
.frame(width:labelWidth, alignment: .leading)
VStack(alignment: .leading) {
ForEach(0 ..< item.val.indices.count) { idx in
Text(item.val\[idx\])
}
}
}
}
}
struct ContentView : View {
@State var items:\[Item\] = \[
Item(label:"Label 1:", val:\["Random texts"\]),
Item(label:"Label 2 Other Size:", val:\["Random texts","Additional text"\]),
Item(label:"Label 3 Other Larger Size:", val:\["Random texts", "Random texts and texts", "Random texts", "Random texts"\])
\]
var body: some View {
GeometryReader { geo in
let labelWidth = geo.size.width * 0.6 // set this however you want to calculate label width
List(items) { item in
ItemRow(labelWidth: labelWidth, item: item)
}
}
}
}][1]][1]
[![struct Item:可识别{
变量id:UUID=UUID()
变量标签:字符串
var val:\[String\]
}
struct ItemRow:视图{
变量标签宽度:CGFloat=0
var项目:项目
var body:一些观点{
HStack(间距:5){
文本(项目标签)
.frame(宽度:labelWidth,对齐:。前导)
VStack(对齐:。前导){
ForEach(0..
最简单的方法是为HStack中的第一个文本()设置一个特定的.frame(宽度:)。然后可以使用.minimumScaleFactor()调整其中文本的大小,以避免单词被截断。下面是一个让您开始学习的示例:
struct ContentView: View {
var body: some View {
VStack {
CustomRow(title: "Label 1:", otherContent: ["Random Texts"])
CustomRow(title: "Label 2 Other Size::", otherContent: ["Random Texts", "Additional Text",])
CustomRow(title: "Label 3 Other Larger Size:", otherContent: ["Random Texts"])
}
}
}
struct CustomRow: View {
let title: String
let otherContent: [String]
var body: some View {
HStack {
Text(title)
.frame(width: 200, alignment: .leading)
.lineLimit(1)
.minimumScaleFactor(0.5)
ForEach(otherContent, id: \.self) { item in
Text(item)
.lineLimit(1)
.minimumScaleFactor(0.1)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
结果:
最简单的方法是为HStack中的第一个文本()设置一个特定的.frame(宽度:)。然后可以使用.minimumScaleFactor()调整其中文本的大小,以避免单词被截断。下面是一个让您开始学习的示例:
struct ContentView: View {
var body: some View {
VStack {
CustomRow(title: "Label 1:", otherContent: ["Random Texts"])
CustomRow(title: "Label 2 Other Size::", otherContent: ["Random Texts", "Additional Text",])
CustomRow(title: "Label 3 Other Larger Size:", otherContent: ["Random Texts"])
}
}
}
struct CustomRow: View {
let title: String
let otherContent: [String]
var body: some View {
HStack {
Text(title)
.frame(width: 200, alignment: .leading)
.lineLimit(1)
.minimumScaleFactor(0.5)
ForEach(otherContent, id: \.self) { item in
Text(item)
.lineLimit(1)
.minimumScaleFactor(0.1)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
结果:
视图之间的平衡宽度
根据所有的回答,我编写了一个更简单的方法,用修改器来实现这一点
首先,我们必须使用视图修改器和宽度获取器添加必要的扩展:
extension View {
func balanceWidth(store width: Binding<CGFloat>, alignment: HorizontalAlignment = .center) -> some View {
modifier(BalancedWidthGetter(width: width, alignment: alignment))
}
@ViewBuilder func `if`<Transform: View>(_ condition: Bool, transform: (Self) -> Transform) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
用法
有了这个,所有的工作都完成了。为了在视图之间获得相等的宽度,我们所要做的就是用balancedWidth
修饰符标记每个视图,并将共享宽度值存储在@状态变量中,初始值==.zero
:
@State var width: CGFloat = 0 <-- Initial value MUST BE == .zero
SomeView()
.balanceWidth(store: $width)
AnotherViewRightAligned()
.balanceWidth(store: $width, alignment: .leading)
通过创建多个@State
变量,我们可以在视图之间创建更多关系,并分别平衡视图之间的宽度。平衡视图之间的宽度
根据所有的回答,我编写了一个更简单的方法,用修改器来实现这一点
首先,我们必须使用视图修改器和宽度获取器添加必要的扩展:
extension View {
func balanceWidth(store width: Binding<CGFloat>, alignment: HorizontalAlignment = .center) -> some View {
modifier(BalancedWidthGetter(width: width, alignment: alignment))
}
@ViewBuilder func `if`<Transform: View>(_ condition: Bool, transform: (Self) -> Transform) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
用法
有了这个,所有的工作都完成了。为了在视图之间获得相等的宽度,我们所要做的就是用balancedWidth
修饰符标记每个视图,并将共享宽度值存储在@状态变量中,初始值==.zero
:
@State var width: CGFloat = 0 <-- Initial value MUST BE == .zero
SomeView()
.balanceWidth(store: $width)
AnotherViewRightAligned()
.balanceWidth(store: $width, alignment: .leading)
通过创建多个@State
变量,我们可以在视图之间创建更多关系并分别平衡它们之间的宽度。这是否回答了您的问题?这是否回答了您的问题?
struct ContentView: View {
@State var width: CGFloat = 0
var body: some View {
VStack(alignment: .leading) {
HStack {
Text("Label 1")
.balanceWidth(store: $width, alignment: .leading)
Text("Textss")
}
HStack {
Text("Label 2: more text")
.balanceWidth(store: $width, alignment: .leading)
Text("Another random texts")
}
HStack {
Text("Label 3: another texts")
.balanceWidth(store: $width, alignment: .leading)
Text("Random texts")
}
}
.padding()
}
}