在 SwiftUI 中拥抱子视图 [英] Hug subviews in SwiftUI

查看:20
本文介绍了在 SwiftUI 中拥抱子视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Dave Abrahams 在他关于自定义视图的 WWDC19 演讲中解释了 SwiftUI 布局的一些机制,但他遗漏了一些内容,我无法正确调整视图的大小.

Dave Abrahams explained some of the mechanics of SwiftUI layouts in his WWDC19 talk about Custom Views, but he left out some bits and I have trouble getting my views properly sized.

有没有办法让 View 告诉它的容器它没有产生任何空间需求,但它会使用它给定的所有空间?另一种说法是容器应该拥抱它的子视图.

具体的例子,我想要类似 c:

Concrete example, I want something like c:

如果你在 VStack 中有一些 Text 就像在 a) 中一样,VStack 将采用它的宽度到最宽的子视图.

If you have some Texts inside a VStack like in a), the VStack will adopt it's width to the widest subview.

如果你在 b) 中添加一个 Rectangle,它会尽可能地扩展,直到 VStack 填满 它的 容器.

If you add a Rectangle though as in b), it will expand as much as it can, until the VStack fills its container.

这表明Texts和Rectangles在布局上属于不同的类别,Text有固定大小和Rectangle 是贪婪的.但是,如果我正在制作自己的View,我如何将其传达给我的容器?

This indicates that Texts and Rectangles are in different categories when it comes to layout, Text has a fixed size and a Rectangle is greedy. But how can I communicate this to my container if I'm making my own View?

我真正想要达到的结果是 c).VStack 在确定其大小时应该忽略 Rectangle(或我的自定义视图),然后一旦完成,然后它应该告诉 Rectangle 或我的自定义视图它可以有多少空间.

The result I actually want to achieve is c). VStack should ignore Rectangle (or my custom view) when it determines its size, and then once it has done that, then it should tell Rectangle, or my custom view, how much space it can have.

鉴于 SwiftUI 似乎自下而上布局,也许这是不可能的,但似乎应该有some 方法来实现这一点.

Given that SwiftUI seems to layout bottom-up, maybe this is impossible, but it seems that there should be some way to achieve this.

推荐答案

没有修饰符 (AFAIK) 来实现这一点,所以这是我的方法.如果这是您经常使用的东西,可能值得创建您自己的修饰符.

There is no modifier (AFAIK) to accomplish this, so here's my approach. If this is something you are going to use too often, it could be worth creating your own modifier.

另请注意,这里我使用的是标准首选项,但锚点首选项更好.在这里解释是一个沉重的话题.我写了一篇文章,你可以在这里查看:https://swiftui-lab.com/communicating-with-the-view-tree-part-1/

Also note that here I am using standard preferences, but anchor preferences are even better. It is a heavy topic to explain here. I've written an article that you can check here: https://swiftui-lab.com/communicating-with-the-view-tree-part-1/

您可以使用下面的代码来完成您要查找的内容.

You can use the code below to accomplish what you are looking for.

import SwiftUI

struct MyRectPreference: PreferenceKey {
    typealias Value = [CGRect]

    static var defaultValue: [CGRect] = []

    static func reduce(value: inout [CGRect], nextValue: () -> [CGRect]) {
        value.append(contentsOf: nextValue())
    }
}

struct ContentView : View {
    @State private var widestText: CGFloat = 0

    var body: some View {
        VStack {
            Text("Hello").background(RectGetter())
            Text("Wonderful World!").background(RectGetter())
            Rectangle().fill(Color.blue).frame(width: widestText, height: 30)
            }.onPreferenceChange(MyRectPreference.self, perform: { prefs in
                for p in prefs {
                    self.widestText = max(self.widestText, p.size.width)
                }
            })
    }
}

struct RectGetter: View {

    var body: some View {
        GeometryReader { geometry in
            Rectangle()
                .fill(Color.clear)
                .preference(key: MyRectPreference.self, value: [geometry.frame(in: .global)])
        }
    }
}

这篇关于在 SwiftUI 中拥抱子视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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