摆动将@State var作为参数传递不会更新视图

时间:2020-08-05 10:29:28

标签: swift animation parameter-passing state

我正在遵循Apple SwingUI开发人员教程,而且我还很新。我目前正在制作动画,对@State变量感到困惑。让我们看下面的代码:

import SwiftUI

struct HikeDetail: View {
    let hike: Hike
    @State var dataToShow = \Hike.Observation.elevation
    
    var buttons = [
        ("Elevation", \Hike.Observation.elevation),
        ("Heart Rate", \Hike.Observation.heartRate),
        ("Pace", \Hike.Observation.pace),
    ]
    
    var body: some View {
        VStack {
            HikeGraph(hike: hike, path: self.dataToShow)
                .frame(height: 200)
            
            HStack(spacing: 25) {
                ForEach(buttons, id: \.0) { value in
                    Button(action: {
                        self.dataToShow = value.1
                    }) {
                        Text(value.0)
                            .font(.system(size: 15))
                            .foregroundColor(value.1 == self.dataToShow
                                ? Color.green
                                : Color.accentColor)
                            .animation(nil)
                    }
                }
            }
        }
    }
}

HikeGraph 是另一个可生成图形的SwiftUI视图,它具有三个选项:

- elevation => gray color
- heartRate  => red color
- pace    => purple color

每个图形都有不同的颜色和形状,但是当我在这三个选项之间切换时,我只会看到一种图形,即最初定义的图形。

    @State var dataToShow = \Hike.Observation.elevation

当我更改以下路径变量时:

    HikeGraph(hike: hike, path: dataToShow)
        .frame(height: 200)

图形不变。但是,当我自己更改dataToShow变量时,我可以观察到颜色的变化。

我的问题是状态变量更改后如何更新图形本身。

编辑:HikeGraph视图

import SwiftUI

func rangeOfRanges<C: Collection>(_ ranges: C) -> Range<Double>
    where C.Element == Range<Double> {
    guard !ranges.isEmpty else { return 0..<0 }
    let low = ranges.lazy.map { $0.lowerBound }.min()!
    let high = ranges.lazy.map { $0.upperBound }.max()!
    return low..<high
}

func magnitude(of range: Range<Double>) -> Double {
    return range.upperBound - range.lowerBound
}

extension Animation {
    static func ripple(index: Int) -> Animation {
        Animation.spring(dampingFraction: 0.5)
            .speed(2)
            .delay(0.03 * Double(index))
    }
}

struct HikeGraph: View {
    var hike: Hike
    var path: KeyPath<Hike.Observation, Range<Double>>
    
    var color: Color {
        switch path {
        case \.elevation:
            return .gray
        case \.heartRate:
            return Color(hue: 0, saturation: 0.5, brightness: 0.7)
        case \.pace:
            return Color(hue: 0.7, saturation: 0.4, brightness: 0.7)
        default:
            return .black
        }
    }
    
    var body: some View {
        let data = hike.observations
        let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
        let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
        let heightRatio = (1 - CGFloat(maxMagnitude / magnitude(of: overallRange))) / 2

        return GeometryReader { proxy in
            HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
                ForEach(data.indices) { index in
                    GraphCapsule(
                        index: index,
                        height: proxy.size.height,
                        range: data[index][keyPath: self.path],
                        overallRange: overallRange)
                    .colorMultiply(self.color)
                    .transition(.slide)
                    .animation(.ripple(index: index))
                }
                .offset(x: 0, y: proxy.size.height * heightRatio)
            }
        }
    }
}

0 个答案:

没有答案