SwiftUI View结构,无需重新加载

问题描述 投票:3回答:1

我想在SwiftUI中创建一个繁星点点的背景视图,该视图使用Double.random()随机定位星星,但是在父视图重新加载var body时不重新初始化它们并移动它们。

struct ContentView: View {
    @State private var showButton = true

    var body: some View {
        ZStack {
            BackgroundView()
            if showButton {
                Button("Tap me"){
                    self.showButton = false
                }
            }
        }
    }
}

我这样定义了我的背景视图。

struct BackgroundView: View {
    var body: some View {
        ZStack {
            GeometryReader { geometry in
                Color.black
                ForEach(0..<self.getStarAmount(using: geometry), id: \.self){ _ in
                    Star(using: geometry)
                }
                LinearGradient(gradient: Gradient(colors: [.purple, .clear]), startPoint: .bottom, endPoint: .top)
                    .opacity(0.7)
            }
        }
    }

    func getStarAmount(using geometry: GeometryProxy) -> Int {
        return Int(geometry.size.width*geometry.size.height/100)
    }
}

[Star定义为

struct Star: View {
    let pos: CGPoint
    @State private var opacity = Double.random(in: 0.05..<0.4)

    init(using geometry: GeometryProxy) {
        self.pos = CGPoint(x: Double.random(in: 0..<Double(geometry.size.width)), y: Double.random(in: 0..<Double(geometry.size.height)))
    }



    var body: some View {
        Circle()
            .foregroundColor(.white)
            .frame(width: 2, height: 2)
            .scaleEffect(CGFloat(Double.random(in: 0.25...1)))
            .position(pos)
            .opacity(self.opacity)
            .onAppear(){
                withAnimation(Animation.linear(duration: 2).delay(Double.random(in: 0..<6)).repeatForever()){
                    self.opacity = self.opacity+0.5
                }
            }
    }
}

正如人们所看到的,Star的动画(以创建“随机”闪烁效果)及其位置都严重依赖于随机值。但是,当重绘BackgroundView(在此示例中为ContentView)的父视图时,所有Star都会被重新初始化,它们的位置值会改变,并且它们会在屏幕上移动。如何最好地防止这种情况?

我尝试了几种方法来防止重新初始化职位。我可以将struct StarCollection创建为static letBackgroundView,但这很麻烦。要使View依赖于随机值(位置),只确定一次这些位置,最好的方法是什么?


此外,渲染速度非常慢。我试图在.drawingGroup()上调用ForEach,但是这似乎会干扰动画的不透明度插值。是否有任何可行的方法来加速具有许多Circle()元素的视图的创建/重新渲染?

swift random swiftui
1个回答
2
投票
缓慢的效果来自onAppear中过于复杂的动画设置,您只需要更改self.opacity状态即可启动动画,因此请移出动画并直接添加到形状中。

Circle() .foregroundColor(.white) .frame(width: 2, height: 2) .scaleEffect(CGFloat(Double.random(in: 0.25...1))) .position(pos) .opacity(self.opacity) .animation(Animation.linear(duration: 0.2).delay(Double.random(in: 0..<6)).repeatForever()) .onAppear(){ // withAnimation{ //(Animation.linear(duration: 2).delay(Double.random(in: 0..<6)).repeatForever()){ self.opacity = self.opacity+0.5 // } }

© www.soinside.com 2019 - 2024. All rights reserved.