Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
375 views
in Technique[技术] by (71.8m points)

ios - How to make a view's height animate from 0 to height in SwiftUI?

I'd like to make this bar's height (part of a larger bar graph) animate on appear from 0 to it's given height, but I can't quite figure it out in SwiftUI? I found this code that was helpful, but with this only the first bar (of 7) animates ??

struct BarChartItem: View {
    
    var value: Int
    var dayText: String
    var topOfSCaleColorIsRed: Bool
    
    @State var growMore: CGFloat = 0
    @State var showMore: Double = 0
    
    var body: some View {
        VStack {
            Text("(value)%")
                .font(Font.footnote.monospacedDigit())
            RoundedRectangle(cornerRadius: 5.0)
                .fill(getBarColor())
                .frame(width: 40, height: growMore)
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                        withAnimation(.linear(duration: 7.0)) {
                            growMore = CGFloat(value)
                            showMore = 1
                        }
                    }
                }.opacity(showMore)
            Text(dayText.uppercased())
                .font(.caption)
            
            
        }
        
    }

And this is the chart:

 HStack(alignment: .bottom) {
                    ForEach(pastRecoveryScoreObjects) { pastRecoveryScoreObject in
                        BarChartItem(value: pastRecoveryScoreObject.recoveryScore, dayText: "(pastRecoveryScoreObject.date.weekdayName)", topOfSCaleColorIsRed: false)
                    }
                }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This works: you can get the index of the ForEach loop and delay each bar's animation by some time * that index. All the bars are connected to the same state variable via a binding, and the state is set immediately on appear. You can play with the parameters to tune it to your own preferences.

struct TestChartAnimationView: View {
    let values = [200, 120, 120, 90, 10, 80]
    @State var open = false
    
    var animationTime: Double = 0.25
    
    var body: some View {
        VStack {
            Spacer()
            HStack(alignment: .bottom) {
                ForEach(values.indices, id: .self) { index in
                    BarChartItem(open: $open, value: values[index])
                        .animation(
                            Animation.linear(duration: animationTime).delay(animationTime * Double(index))
                        )
                }
            }
        }
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                open = true
            }
        }
    }
}

struct BarChartItem: View {
    @Binding var open: Bool
    var value: Int
    
    var body: some View {
        VStack {
            Text("(value)%")
                .font(Font.footnote.monospacedDigit())
            RoundedRectangle(cornerRadius: 5.0)
                .fill(Color.blue)
                .frame(width: 20, height: open ? CGFloat(value) : 0)
            Text("Week".uppercased())
                .font(.caption)
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...