如何让SwiftUI忘记内部状态

如何让SwiftUI忘记内部状态,swiftui,Swiftui,我有如下观点 struct A: View { var content: AnyView var body: some View { ScrollView(.vertical, showsIndicators: false) { VStack { // Common Elements content // More Common Elements

我有如下观点

struct A: View {
    var content: AnyView
    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            VStack {
                // Common Elements
                content
                // More Common Elements
            }
        }
    }
}
当我从另一个角度,比如

A(nextInnerView())

发生了两件事。首先,当
内容的大小改变时,
元素会改变ScrollView的动画效果。其次,如果向下滚动然后更改
内容
,滚动位置不会重置。

下面是可能解决方案的演示。使用Xcode 11.4/iOS 13.4进行测试

这种行为的根源在于SwiftUI渲染优化,即尝试仅重新渲染更改的部分,因此方法是根据访谈更改产生的条件识别视图A(将其标记为完全更改),或者,也可以仅通过
UUID()
来识别视图A

struct testinnerviewPlacement:视图{
@状态专用变量计数器=0
var body:一些观点{
VStack{
按钮(“下一步”){self.counter+=1}
分隔器()
A(内容:nextInnerView())
.id(计数器)//AnyView{
任意视图(组){
如果计数器%2==0{
文本(“文本演示”)
}否则{
图像(系统名称:“星”)
.可调整大小()
.框架(宽度:100,高度:100)
}
})
}
}
结构A:视图{
var内容:AnyView
var body:一些观点{
滚动视图(.vertical,showsIndicators:false){
VStack{

ForEach(0..谢谢!它通过滚动解决了这个问题。仍然很有趣地重新绘制。想象一个容器底部有两个按钮。当内部视图从一个很长的按钮更改为一个很短的按钮时,按钮会通过动画向上移动到新位置。@vasily,只是替换了较低的内容(蓝色矩形)带有HStack中的按钮-不可复制(没有动画)提供的方法,所以如果您看到一些,那么它是其他一些代码。
struct TestInnerViewReplacement: View {
    @State private var counter = 0
    var body: some View {
        VStack {
            Button("Next") { self.counter += 1 }
            Divider()
            A(content: nextInnerView())
               .id(counter)              // << here !!
        }
    }

    private func nextInnerView() -> AnyView {
        AnyView(Group {
            if counter % 2 == 0 {
                Text("Text Demo")
            } else {
                Image(systemName: "star")
                    .resizable()
                    .frame(width: 100, height: 100)
            }
        })
    }
}

struct A: View {
    var content: AnyView

    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            VStack {
                ForEach(0..<5) { _ in      // upper content demo 
                    Rectangle().fill(Color.yellow)
                        .frame(height: 40)
                        .frame(maxWidth: .infinity)
                        .padding()
                }

                content

                ForEach(0..<10) { _ in    // lower content demo
                    Rectangle().fill(Color.blue)
                        .frame(height: 40)
                        .frame(maxWidth: .infinity)
                        .padding()
                }
            }
        }
    }
}