如何在 AppKit 上的自定义 SwiftUI 表单中右对齐项目标签? [英] How to right-align item labels in a custom SwiftUI form on AppKit?

查看:15
本文介绍了如何在 AppKit 上的自定义 SwiftUI 表单中右对齐项目标签?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 Cocoa 表格:

I have the following Cocoa form:

struct Canvas: PreviewProvider {
  static var previews: some View {
    VStack {
      HStack(alignment: .firstTextBaseline) {
        Text("Endpoint:")
        TextField("https://localhost:8080/api", text: .constant(""))
      }
      Divider()
      HStack(alignment: .firstTextBaseline) {
        Text("Path:")
        TextField("/todos", text: .constant(""))
      }
      Spacer()
    }
    .padding()
    .previewLayout(.fixed(width: 280, height: 200))
  }
}

这个面板看起来不错,但我想右对齐端点:"和路径:"标签:

This panel looks nice but I’d like to right-align "Endpoint:" and "Path:" labels:

所以我应用了自定义的水平对齐方式:

So I apply a custom horizontal alignment:

struct Canvas: PreviewProvider {
  static var previews: some View {
    VStack(alignment: .label) {
      HStack(alignment: .firstTextBaseline) {
        Text("Endpoint:").alignmentGuide(.label) { $0[.trailing] }
        TextField("https://localhost:8080/api", text: .constant(""))
      }
      Divider()
      HStack(alignment: .firstTextBaseline) {
        Text("Path:").alignmentGuide(.label) { $0[.trailing] }
        TextField("/todos", text: .constant(""))
      }
      Spacer()
    }
    .padding()
    .previewLayout(.fixed(width: 280, height: 200))
  }
}

extension HorizontalAlignment {
  private enum Label: AlignmentID {
    static func defaultValue(in context: ViewDimensions) -> CGFloat {
      context[.leading]
    }
  }
  static let label: HorizontalAlignment = .init(Label.self)
}

结果不是我需要的:

没有文档,请帮忙.

推荐答案

我不相信对齐指南会在其当前的实现中发挥作用.在和他们玩了一会儿之后,似乎他们根据容器的给定大小来调整孩子的大小然后根据指南对齐每个孩子.这会导致您看到的奇怪行为.

I don't believe alignment guides will work here in their current implementation. After playing with them a bit, it seems that they size their children based on the container's given size and then align each child based on the guide. This leads to the weird behavior you were seeing.

下面我展示了 3 种不同的技术,它们可以让您按复杂程度获得想要的结果.在这个特定示例之外,每个都有其应用.

Below I show 3 different techniques that will allow you to get your desired results, in order of complexity. Each has its applications outside of this specific example.

最后一个 (label3()) 对于较长的表单将是最可靠的.

The last (label3()) will be the most reliable for longer forms.


struct ContentView: View {
    @State var sizes: [String:CGSize] = [:]

    var body: some View {
        VStack {
            HStack(alignment: .firstTextBaseline) {
                self.label3("Endpoint:")
                TextField("https://localhost:8080/api", text: .constant(""))
            }
            Divider()
            HStack(alignment: .firstTextBaseline) {
                self.label3("Path:")
                TextField("/todos", text: .constant(""))
            }
        }
        .padding()
        .onPreferenceChange(SizePreferenceKey.self) { preferences in
            self.sizes = preferences
        }
    }

    func label1(_ text: String) -> some View {
        Text(text) // Use a minimum size based on your best guess.  Look around and you'll see that many macOS apps actually lay forms out like this because it's simple to implement.
            .frame(minWidth: 100, alignment: .trailing)
    }

    func label2(_ text: String, sizer: String = "Endpoint:") -> some View {
        ZStack(alignment: .trailing) { // Use dummy content for sizing based on the largest expected item.  This can be great when laying out icons and you know ahead of time which will be the biggest.
            Text(sizer).opacity(0.0)
            Text(text)
        }
    }

    func label3(_ text: String) -> some View {
        Text(text) // Use preferences and save the size of each label
        .background(
            GeometryReader { proxy in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: [text : proxy.size])
            }
        )
        .frame(minWidth: self.sizes.values.map { $0.width }.max() ?? 0.0, alignment: .trailing)
    }
}

struct SizePreferenceKey: PreferenceKey {
    typealias Value = [String:CGSize]
    static var defaultValue: Value = [:]

    static func reduce(value: inout Value, nextValue: () -> Value) {
        let next = nextValue()
        for (k, v) in next {
            value[k] = v
        }
    }
}

这是带有 label2label3 的结果的屏幕截图.

Here's a screenshot of the results with label2 or label3.

这篇关于如何在 AppKit 上的自定义 SwiftUI 表单中右对齐项目标签?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆