ios - 为什么 SwiftUI 中的动画会跳来跳去
问题描述
目标是有一个闪烁的加载动画。像 facebook 和许多其他应用程序一样使用。
如果我把它放在 TabView 中,它会按预期工作,但如果我在 NavigationView 中有代码,它会像在视频中一样跳来跳去。为什么会这样?
如果有人可以指导我找到一个很棒的解决方案!
视频: https ://imgur.com/a/wZ3jI1f
这是代码:
import SwiftUI
struct ShimmeringListView: View {
public var body: some View {
return VStack {
ShimmeringCell()
ShimmeringCell()
}
}
}
private struct ShimmeringCell: View {
@State private var opacity: Double = Constants.minOpacity
public var body: some View {
cardShimmerAnimation
}
var cardShimmerAnimation: some View {
VStack {
ZStack {
backgroundRectangle
shimmerRectangles
}
}
.padding(.bottom, 20)
.padding(.top, 16)
}
var backgroundRectangle: some View {
Rectangle()
.fill(
LinearGradient(
gradient: Gradient(stops: [
Gradient.Stop(color: .lightGray, location: 0.476),
Gradient.Stop(color: .white, location: 0.524)
]),
startPoint: .top,
endPoint: .bottom))
.frame(height: 269)
.cornerRadius(Constants.cornerRadius)
.padding(.horizontal, 15)
}
var shimmerRectangles: some View {
VStack {
oneRectangle
.frame(height: 28)
.padding(.trailing, 73)
.padding(.bottom, 2)
oneRectangle
.frame(height: 20)
.padding(.trailing, 188)
.padding(.bottom, 2)
oneRectangle
.frame(height: 20)
.padding(.trailing, 130)
.padding(.bottom, 20)
oneRectangle
.frame(height: 20)
.padding(.trailing, 188)
.padding(.vertical, 8)
oneRectangle
.frame(height: 20)
.padding(.trailing, 116)
Divider()
.padding(.horizontal, 32)
.padding(.vertical, 8)
oneRectangle
.frame(height: 20)
.padding(.trailing, 52)
}
}
var oneRectangle: some View {
let baseAnimation = Animation.easeInOut(duration: Constants.duration)
let repeatedAnimation = baseAnimation.repeatForever(autoreverses: true)
return RoundedRectangle(cornerRadius: Constants.cornerRadius)
.fill(Color.loadingColor)
.opacity(opacity)
.transition(.opacity)
.padding(.leading, 31)
.animation(repeatedAnimation)
.onAppear {
self.opacity = Constants.maxOpacity
}
}
}
private struct Constants {
static let duration: Double = 0.9
static let minOpacity: Double = 0.25
static let maxOpacity: Double = 1.0
static let cornerRadius: CGFloat = 6.0
}
解决方案
您只需要两个小的更改(请参阅代码中内联的注释):
return RoundedRectangle(cornerRadius: Constants.cornerRadius)
.fill(Color.loadingColor)
.opacity(opacity)
.transition(.opacity)
.padding(.leading, 31)
.animation(repeatedAnimation, value: opacity) //<-- Add value: parameter
.onAppear {
DispatchQueue.main.async { //<-- wrap in DispatchQueue.main.async
self.opacity = Constants.maxOpacity
}
}
至于为什么:对于修饰符animation
,不推荐使用animation
不带value
参数的,我们应该期望使用value:
. 对于DispatchQueue
,我最好的猜测是NavigationView
附加了一个隐式动画,我们需要在下一个运行循环中启动这个动画,以确保它是独立的。
推荐阅读
- image-processing - Imagemagick 高密度 zip 转换的文件大小异常小
- reactjs - 如何在 EC2 实例上运行我的测试环境?
- sql - “这个子查询最多可以返回一条记录。”
- javascript - 反应中的AXIOS GET请求循环
- simulation - 如何使用 Anylogic 中的进入和退出块来跨代理类型及其各自的流程图传输代理?
- laravel - Laravel 8 - 强制模式在列定义中添加主键 [已修复]
- linux - Oracle DB回滚段中含义的理论理解问题
- cordova - FCM 推送 - 一次向 iOS 和 android 发送消息,通知对象仅适用于 iOS
- encryption - 使用 2 个私钥加密单个密钥所有者无法访问的内容
- nginx - Nginx 代理负载均衡不允许 POST 大于 1MB