SwiftUI比屏幕更宽,使用alignmentGuide可在另一个视图容器中查看

SwiftUI比屏幕更宽,使用alignmentGuide可在另一个视图容器中查看,swiftui,Swiftui,我正在学习SwiftUI,我读了这篇关于alignmentGuides以及如何对齐不同容器中的视图的非常好的文章: 在我的UI中,我希望有一个复选标记,然后在一行(橙色)上有一个Text()标签问题,然后在下面有一个TextField(),他们可以回答问题(绿色),我希望TextField()的前导与Text()问题的前导匹配。像这样: 上面的屏幕截图是在我使用.frame(宽度:200)强制设置绿色文本字段()的宽度时生成的。我不想强制文本字段保持一定的大小,但是当我 不幸的是,每当我移除.

我正在学习SwiftUI,我读了这篇关于alignmentGuides以及如何对齐不同容器中的视图的非常好的文章:

在我的UI中,我希望有一个复选标记,然后在一行(橙色)上有一个Text()标签问题,然后在下面有一个TextField(),他们可以回答问题(绿色),我希望TextField()的前导与Text()问题的前导匹配。像这样:

上面的屏幕截图是在我使用
.frame(宽度:200)
强制设置绿色文本字段()的宽度时生成的。我不想强制文本字段保持一定的大小,但是当我

不幸的是,每当我移除
.frame(宽度:200)

1) 绿色的TextField()然后延伸到比屏幕更宽的位置 2) 外部VStack也延伸到屏幕之外。 3) 橙色HStack中的复选标记图像()与屏幕的前端对齐

下面是没有
TextField().frame(宽度:200)
时的情况,请注意,VStack的蓝色轮廓位于屏幕两侧:

代码如下:

extension HorizontalAlignment {
    private enum QuestionAlignment : AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[.leading]
        }
    }

    static let questionAlignment = HorizontalAlignment(QuestionAlignment.self)
}

struct EasyModeQuestion: View {

    @Binding var field : String

    var body: some View {
        VStack(alignment: .questionAlignment) {
            Rectangle()
                .fill(Color.primary)
                .frame(width: 1)
                .alignmentGuide(.questionAlignment, computeValue: { d in d[HorizontalAlignment.leading] })

            HStack() {
                Image(systemName: "checkmark.square")

                Text("What is the blah blah blah?")
                    .alignmentGuide(.questionAlignment, computeValue: { d in d[.leading] })

            }.background(Color.orange)


            TextFieldRoundedRect(placeholder: "", text: $field)
                .alignmentGuide(.questionAlignment, computeValue: { d in d[.leading] })
                .background(Color.green)
                //.frame(width: 200)


            Rectangle()
                .fill(Color.primary)
                .frame(width: 1)
                .alignmentGuide(.questionAlignment, computeValue: { d in d[HorizontalAlignment.leading] })
        }

    }
}
上面和下面的两个Rectangle()对象是我问题顶部链接中的示例,它们有助于可视化对齐指南的位置

当我使用基本的前导对齐方式并删除所有对齐辅助线时,TextField()将返回到适当的宽度:


SwiftUI的布局方式与UIKit AutoLayout不同

  • 使子视图计算所有内部内容大小
  • 为它们执行布局
  • 因此,对齐是在
    TextField
    计算其大小后应用的,但
    TextField
    没有自己的大小,因此它会获取父视图建议的所有可能宽度,即屏幕宽度。然后,当应用对齐时,一切都变得一团糟

    因此,您以某种方式将
    TextField
    的大小限制为所需的值(顺便说一句,您没有指定哪个值?)

    案例1:硬编码-就像您使用
    .frame(宽度:200)

    案例2:占位符的固定大小

    TextFieldRoundedRect(placeholder: "your answer is here", text: $field)
        .alignmentGuide(.questionAlignment, computeValue: { d in d[.leading] })
        .background(Color.green)
        .fixedSize()
    


    案例3:动态计算(GeometryReader、AnchorReference等)到您需要的点

    我是您在问题开头引用的文章的作者。对齐确实会带来挑战,不是吗?。在你的情况下,让我提出一种不同的方法。我知道对很多人来说,这件看起来很便宜。。。但它实现了一个非常重要的点:代码的简单性。我知道你的问题可能只是为了暴露你正在处理的问题而简化,如果是这样,那么提供的解决方案可能没有帮助。。。但这里是以防万一:只需使用一个垫片。我可以想出两种简单的方法。一个更快但更脏,另一个更优雅,但需要多行代码:

    #1快速且脏:使用不可见的复选标记图像作为间隔

    struct ContentView:View{
    @国家私有变量text=“”
    var body:一些观点{
    EasyModeQuestion(字段:self.$text)
    .框架(宽度:400)
    }
    }
    结构EasyModeQuestion:视图{
    @绑定变量字段:字符串
    var body:一些观点{
    VStack(对齐:。前导){
    HStack{
    图像(系统名称:“复选标记.方形”)
    文本(“什么是废话?”)
    }
    HStack{
    图像(systemName:“checkmark.square”)。不透明度(0.0)
    TextField(“,text:$field)
    .textFieldStyle(RoundedBorderTextFieldStyle())
    }
    }
    }
    }
    
    #2个更好的间隔?:使用图像的宽度作为颜色。清晰视图

    struct ContentView:View{
    @国家私有变量text=“”
    var body:一些观点{
    EasyModeQuestion(字段:self.$text)
    .框架(宽度:400)
    }
    }
    结构EasyModeQuestion:视图{
    @绑定变量字段:字符串
    var body:一些观点{
    让img=UIImage(系统名:“checkmark.square”)!
    返回VStack(对齐:。前导){
    HStack{
    图像(uiImage:img)
    文本(“什么是废话?”)
    }
    HStack{
    颜色.清晰.边框(宽度:img.size.width,高度:0)
    TextField(“,text:$field)
    .textFieldStyle(RoundedBorderTextFieldStyle())
    }
    }
    }
    }
    
    但是文本字段不仅仅占据了所有可用的大小,它还扩展到比屏幕更宽。如果我去掉所有的对齐,那么文本字段的大小是正确的。谢谢你的文章,谢谢你的回复!我可能会使用这些更脏的解决方案,但你知道为什么对齐位一开始就不起作用吗?我不喜欢假设这样的事情是错误的,尤其是当我知道SwiftUI有一个不同于我习惯的思维模式,这可能只是一些我不理解的东西。