【问题标题】:Get width of a view using in SwiftUI在 SwiftUI 中使用获取视图的宽度
【发布时间】:2019-12-25 21:31:04
【问题描述】:

我需要在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)
    }
}

【问题讨论】:

    标签: swift swiftui frame


    【解决方案1】:

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

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

    将其内容定义为自身大小和坐标空间的函数的容器视图。 Apple Doc

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

    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)
        }
    }
    

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

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

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

    阅读更多示例:

    【讨论】:

    • 如果我不计算尺寸,那么我将如何实现类似于dropbox.com/s/p4m47u3fhup7o8j/2.png?dl=0 的布局
    • 我的意思是,我需要知道一个单元格的宽度才能计算一行中的单元格数。
    • @MaxPower mmh 我建议您打开一个标题为“如何计算一行中的单元格数”的新问题,尝试查看github.com/Q-Mobile/QGrid
    • @GiuseppeSapienza 感谢这个不错的解决方案。您知道为什么需要拨打DispatchQueue.main.async {...} 才能工作吗?我还以为makeView() 已经在主线程上运行了。
    【解决方案2】:

    获取子视图的尺寸是任务的第一部分。第二部分是提高维度的价值。 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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-05-18
      • 1970-01-01
      • 2019-10-23
      • 1970-01-01
      • 1970-01-01
      • 2012-12-08
      • 1970-01-01
      • 2021-08-07
      相关资源
      最近更新 更多