在 SwiftUI 中使用获取视图的宽度

Ale*_*aev 27 frame swift swiftui

我需要在 中获取渲染视图的宽度SwiftUI,这显然不是那么容易。

我的看法是,我需要一个返回视图尺寸的函数,就这么简单。

var body: some View {
    VStack(alignment: .leading) {
        Text(timer.name)
            .font(.largeTitle)
            .fontWeight(.heavy)
        Text(timer.time)
            .font(.largeTitle)
            .fontWeight(.heavy)
            .opacity(0.5)
    }
}
Run Code Online (Sandbox Code Playgroud)

Giu*_*nza 39

获取 a 尺寸的唯一方法View是使用 a GeometryReader。读取器返回容器的尺寸。

什么是几何阅读器?文档说:

一个容器视图,将其内容定义为其自身大小和坐标空间的函数。苹果文档

所以你可以通过这样做来获得尺寸:

struct ContentView: View {
    
   @State var frame: CGSize = .zero
    
    var body: some View {
        HStack {
            GeometryReader { (geometry) in
                self.makeView(geometry)
            }
        }
        
    }
    
    func makeView(_ geometry: GeometryProxy) -> some View {
        print(geometry.size.width, geometry.size.height)

        DispatchQueue.main.async { self.frame = geometry.size }

        return Text("Test")
                .frame(width: geometry.size.width)
    }
}
Run Code Online (Sandbox Code Playgroud)

打印尺寸是HStack内视图容器的尺寸。

您可能会使用另一个GeometryReader来获取内部维度。

但请记住,SwiftUI 是一个声明式框架。所以你应该避免计算视图的尺寸:

阅读更多示例:

  • @GiuseppeSapienza 感谢这个很好的解决方案。您知道为什么需要调用“DispatchQueue.main.async {...}”才能工作吗?我本以为 ```makeView()``` 已经在主线程上运行了。 (3认同)

Pau*_*l B 20

获取子视图的尺寸是任务的第一部分。将维度值向上冒泡是第二部分。GeometryReader获取父视图的暗淡,这可能不是您想要的。为了让这个孩子视图的变暗,我们可以称之为一个修饰在具有实际尺寸,例如其子视图.background().overlay()

struct GeometryGetterMod: ViewModifier {

    @Binding var rect: CGRect

    func body(content: Content) -> some View {
        print(content)
        return GeometryReader { (g) -> Color in // (g) -> Content in - is what it could be, but it doesn't work
            DispatchQueue.main.async { // to avoid warning
                self.rect = g.frame(in: .global)
            }
            return Color.clear // return content - doesn't work
        }
    }
}

struct ContentView: View {
    @State private var rect1: CGRect = CGRect()
    var body: some View {
        let t = HStack {
            // make two texts equal width, for example
            // this is not a good way to achieve this, just for demo
            Text("Long text").overlay(Color.clear.modifier(GeometryGetterMod(rect: $rect1)))
            // You can then use rect in other places of your view:

            Text("text").frame(width: rect1.width, height: rect1.height).background(Color.green)
            Text("text").background(Color.yellow)
        }
        print(rect1)
        return t
    }
}
Run Code Online (Sandbox Code Playgroud)