SwiftUI 列表动画
Posted
技术标签:
【中文标题】SwiftUI 列表动画【英文标题】:SwiftUI list animations 【发布时间】:2020-04-19 20:48:29 【问题描述】:我正在关注 Apple 的 Swift UI Animating Views And Transitions,我注意到 Hike Graph View 中有一个错误。当我点击图表时,它不允许我从海拔切换到心率或配速。它不允许我,只是退出视图。我认为这与此处的列表有关:
VStack(alignment: .leading)
Text("Recent Hikes")
.font(.headline)
HikeView(hike: hikeData[0])
远足视图包含:
import SwiftUI
struct HikeView: View
var hike: Hike
@State private var showDetail = false
var transition: AnyTransition
let insertion = AnyTransition.move(edge: .trailing)
.combined(with: .opacity)
let removal = AnyTransition.scale
.combined(with: .opacity)
return .asymmetric(insertion: insertion, removal: removal)
var body: some View
VStack
HStack
HikeGraph(hike: hike, path: \.elevation)
.frame(width: 50, height: 30)
.animation(nil)
VStack(alignment: .leading)
Text(hike.name)
.font(.headline)
Text(hike.distanceText)
Spacer()
Button(action:
withAnimation
self.showDetail.toggle()
)
Image(systemName: "chevron.right.circle")
.imageScale(.large)
.rotationEffect(.degrees(showDetail ? 90 : 0))
.scaleEffect(showDetail ? 1.5 : 1)
.padding()
if showDetail
HikeDetail(hike: hike)
.transition(transition)
远足细节包含:
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
return VStack
HikeGraph(hike: hike, path: 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.gray
: Color.accentColor)
.animation(nil)
远足 Graoh 包含:
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)
图形胶囊包含:
import SwiftUI
struct GraphCapsule: View
var index: Int
var height: CGFloat
var range: Range<Double>
var overallRange: Range<Double>
var heightRatio: CGFloat
max(CGFloat(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
var offsetRatio: CGFloat
CGFloat((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
var body: some View
Capsule()
.fill(Color.white)
.frame(height: height * heightRatio)
.offset(x: 0, y: height * -offsetRatio)
有没有办法解决这个问题?谢谢
【问题讨论】:
【参考方案1】:问题可能在 SwiftUI 中更深——如果您在 HikeGraph 中注释掉 transition(.slide)(并重新启动 XCODE),它将开始工作
【讨论】:
以上是关于SwiftUI 列表动画的主要内容,如果未能解决你的问题,请参考以下文章