1

我不是 SwiftUI 的老手,但我已经发布了几个中等复杂度的应用程序。不过,我不能声称我完全理解它,我希望有更深入了解的人可以对这个问题有所了解:

我有一些想要打开和关闭的内容,与.sheet()不同,但我想要更多地控制它。这是一些“重构”的代码,但它应该能够抓住本质:

struct ContentView: View {

    @State private var isShown = false

    var body: some View {

        GeometryReader { g in

            VStack {

                ZStack(alignment: .top) {

                    // This element "holds" the size
                    // while the content is hidden
                    Color.clear

                    // Content to be toggled
                    if self.isShown {
                        ScrollView {
                            Rectangle()
                                .aspectRatio(1, contentMode: .fit)
                                .frame(width: g.size.width) // This is a "work-around"
                        } // ScrollView
                            .transition(.move(edge: .bottom))
                            .animation(.easeOut)
                    }

                } // ZStack

                // Button to show / hide the content
                Button(action: {
                    self.isShown.toggle()
                }) {
                    Text(self.isShown ? "Hide" : "Show")
                }

            } // VStack

        } // GeometryReader

    }
}

它的作用是打开和关闭一些内容块(这里由ScrollView中的Rectangle表示)。发生这种情况时,内容视图会通过一些动画从底部移入进行过渡。再次点击按钮时会发生相反的情况。

这段特定的代码按预期工作,但仅仅是因为这一行:

.frame(width: g.size.width) // This is a "work-around"

反过来,这需要一个额外的GeometryReader,否则,内容的宽度会被动画化,从而产生不需要的效果(我发现的另一个“修复”是使用.fixedSize()修饰符,但是为了产生合理的效果,它需要假定其自身宽度的内容,如Text

我对明智的问题是:是否可以在不使用此类“修复”的情况下很好地转换封装在ScrollView中的内容?或者,是否有更优雅的解决方法?

@Asperi 回答后的问题的快速补充:内容应保持动画。你是我唯一的希望,

——巴格兰

4

1 回答 1

1

这是一个解决方案(已更新bodyw/o GeometryReader)。使用 Xcode 11.4 / iOS 13.4 测试

演示

var body: some View {
    VStack {
        ZStack(alignment: .top) {
            // This element "holds" the size
            // while the content is hidden
            Color.clear

            // Content to be toggled
            if self.isShown {
                ScrollView {
                    Rectangle()
                        .aspectRatio(1, contentMode: .fit)
                        .animation(nil)     // << here !!
                } // ScrollView
                    .transition(.move(edge: .bottom))
                    .animation(.easeOut)
            }
        } // ZStack

        // Button to show / hide the content
        Button(action: {
            self.isShown.toggle()
        }) {
            Text(self.isShown ? "Hide" : "Show")
        }
    } // VStack
}
于 2020-06-06T10:36:23.670 回答