使用SwiftUI,是否可以将视图的大小限制为另一个非兄弟视图?

时间:2020-03-17 16:37:35

标签: swift swiftui

我在摆弄一个视图布局-一个图形-在这里我看到在全Swift布局中可以走多远。每个组件都很好,但是组装整个组件并没有达到我想要的效果。我发现,我可以轻松地沿单个堆栈轴限制大小,而不能一次限制两个轴(垂直和水平)。

正如我发现you can align non-siblings with a custom guide一样,我开始接触AlignmentGuides。这将有助于我的目标,但并不能解决定型部分,这是此问题的核心:

是否有一种方法可以基于另一个非同级视图来限制视图的大小?

结构的简化为:

HStack {
   CellOneView {
   }
   CellTwoView {
   }
}
HStack {
   CellThreeView {
   }
   CellFourView {
   }
}

哪个映射到:

+-----+-----+
|  1  |  2  |
+-----+-----+
|  3  |  4  |
+-----+-----+

是否可以告诉CellFour(与单元格1和2不在同一个HStack中),我希望它将自身约束(并对齐)到单元格CellTwo的宽度?

这不一定严格是网格视图(example of grid view)。在这种情况下,我实际上只关心三个视图-大致映射到单元格1,单元格2和单元格4的区域。我希望单元格1和单元格2的高度相同(可以容易地通过当前HStack),并且单元2和单元4的宽度相同-这就是我在努力的地方。

2 个答案:

答案 0 :(得分:2)

由于您已经开始使用对齐向导,因此可以使用此仪器。这是可能的方法(针对您的抓痒示例):

@State private var width: CGFloat = 10 // < initial value does not much matter
...

HStack {
   CellOneView {
   }
   CellTwoView {
   }
    .alignmentGuide(VerticalAlignment.center, computeValue: { d in
        // for simplicity of demo skipped checking for equality
        DispatchQueue.main.async { // << must be async
            self.width = d.width   // << set limit
        }
        return d[VerticalAlignment.center]
    })

}
HStack {
   CellThreeView {
   }
   CellFourView {
   }
   .frame(width: self.width) // << apply limit, updated right in next loop
}

答案 1 :(得分:2)

1。获取尺寸

struct CellTwoView: View {

    var body: some View {
        Rectangle()
            .background(
                GeometryReader(content: { (proxy: GeometryProxy) in
                    Color.clear
                        .preference(key: MyPreferenceKey.self, value: MyPreferenceData(rect: proxy.size))
                })
        )
    }
}

说明-在这里,我已经从使用background View(Color.clear)获得了视图的大小,除非从CellTwoView本身获得了它的大小,否则我将使用此技巧。 “ SwiftUI-View大小的原因由视图本身确定,如果它们具有大小(父级不能像UIKit那样更改大小)。因此,如果我将GeometryReader与CellTwoView本身一起使用,则GeometryReader会占用CellTwoView的 parent 中可用的大小。 ->原因-> GeometryReader取决于其父级大小。 (实际上这是另一个主题,也是SwiftUI中的主要内容)

键->

struct MyPreferenceKey: PreferenceKey {
            static var defaultValue: MyPreferenceData = MyPreferenceData(size: CGSize.zero)


        static func reduce(value: inout MyPreferenceData, nextValue: () -> MyPreferenceData) {
            value = nextValue()
        }

        typealias Value = MyPreferenceData
    }

值(及其首选项更改时的处理方式)->

struct MyPreferenceData: Equatable {
    let size: CGSize
    //you can give any name to this variable as usual.
}

2。将尺寸应用于其他视图

struct ContentView: View {

    @State var widtheOfCellTwoView: CGFloat = .zero

    var body: some View {
        VStack {
            HStack {
                CellOneView()
                CellTwoView ()
                    .onPreferenceChange(MyPreferenceKey.self) { (prefereneValue) in
                        self.widtheOfCellTwoView = prefereneValue.size.width
                }
            }

            HStack {
                CellThreeView ()
                CellFourView ()
                    .frame(width: widtheOfCellTwoView)
            }
        }
    }
}