在SwiftUI中设置闪烁铃声的动画

在SwiftUI中设置闪烁铃声的动画,swift,swiftui,Swift,Swiftui,我在SwiftUI中制作简单的系统图标flash时遇到问题。 我让动画工作,但它有一个愚蠢的行为,如果布局的 懒散的GridView会改变或适应。下面是其错误行为的视频。 闪烁的钟形物保持在原位,但当布局重新排列钟形物时 从不再存在的父视图的底部开始转换 有人有没有建议如何避开这个问题 下面是一个与我的问题类似的工作示例 import SwiftUI struct FlashingBellLazyVGrid: View { @State var isAnimating = false

我在SwiftUI中制作简单的系统图标flash时遇到问题。 我让动画工作,但它有一个愚蠢的行为,如果布局的 懒散的GridView会改变或适应。下面是其错误行为的视频。 闪烁的钟形物保持在原位,但当布局重新排列钟形物时 从不再存在的父视图的底部开始转换

有人有没有建议如何避开这个问题

下面是一个与我的问题类似的工作示例

import SwiftUI

struct FlashingBellLazyVGrid: View {
    @State var isAnimating = false
    @State var showChart = true
    
    var body: some View {
        
        let columns = [GridItem(.adaptive(minimum: 300), spacing: 50, alignment: .center)]
        
        
        VStack {
            Button(action: {
                showChart.toggle()
            }) {
                VStack {
                    Circle()
                        .fill(showChart ? Color.green : Color.red)
                        .shadow(color: Color.gray, radius: 5, x: 2, y: 2)
                    Text("Charts")
                        .foregroundColor(Color.primary)
                    
                }.frame(width: 150, height: 50)
            }
            
            ScrollView {
                LazyVGrid (
                    columns: columns, spacing: 50
                    ) {
                    
                   
                    ForEach(0 ..< 25) { item in
                        ZStack {
                            Rectangle()
                                .fill(Color.red)
                                .cornerRadius(15)
                            
                            VStack {
                                HStack {
                                    Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
                                    Spacer()
                                    Image(systemName: "bell.fill")
                                        .foregroundColor(Color.yellow)
                                        .opacity(self.isAnimating ? 1 : 0)
                                        .animation(Animation.easeInOut(duration: 0.66).repeatForever(autoreverses: false))
                                        .onAppear{ self.isAnimating = true }
                                }.padding(50)
                                if showChart {
                                Rectangle()
                                    .fill(Color.green)
                                    .frame(height: 200)
                                }
                            }
                        }
                    }
                   
                                                       
                }
            }
        }
        
    }
}

struct FlashingBellLazyVGrid_Previews: PreviewProvider {
    static var previews: some View {
        FlashingBellLazyVGrid()
    }
}
导入快捷界面
结构FlashingBellLazyVGrid:视图{
@状态变量isAnimating=false
@状态变量showChart=true
var body:一些观点{
let columns=[GridItem(.adaptive(最小值:300),间距:50,对齐方式:。居中)]
VStack{
按钮(操作:{
showChart.toggle()
}) {
VStack{
圈()
.fill(显示图?颜色。绿色:颜色。红色)
.阴影(颜色:颜色.灰色,半径:5,x:2,y:2)
文本(“图表”)
.foregroundColor(颜色.primary)
}.框架(宽度:150,高度:50)
}
滚动视图{
懒散网格(
列:列,间距:50
) {
ForEach(0..<25){
ZStack{
矩形()
.填充(颜色.红色)
.转弯半径(15)
VStack{
HStack{
文本(/*@START\u MENU\u TOKEN@*/“你好,世界!”/*@END\u MENU\u TOKEN@*/)
垫片()
图像(系统名称:“bell.fill”)
.foregroundColor(颜色.黄色)
.不透明度(自扩散?1:0)
.animation(animation.easeInOut(持续时间:0.66)。repeatForever(自动反转:false))
.onAppear{self.isAnimating=true}
}.填充(50)
如果显示图{
矩形()
.填充(颜色.绿色)
.框架(高度:200)
}
}
}
}
}
}
}
}
}
结构FlashingBellLazyVGrid\u预览:预览提供程序{
静态var预览:一些视图{
FlashingBellLazyVGrid()
}
}
单击顶部的showChart按钮之前的外观

切换按钮后,铃声似乎从屏幕底部错误地移动到位。将其切换回原始状态并不能解决随后出现的错误

[


看起来动画是基于视图的原始大小。为了诱使它识别新的视图大小,我使用了
.id(UUID())
在网格外部。在现实世界的应用程序中,您可能希望小心地将此ID存储在某个位置,并仅在需要时刷新它——而不是像我这样在每次重新渲染时都刷新:


struct FlashingBellLazyVGrid: View {
    @State var showChart = true
    
    let columns = [GridItem(.adaptive(minimum: 300), spacing: 50, alignment: .center)]
    
    var body: some View {
        VStack {
            Button(action: {
                showChart.toggle()
            }) {
                VStack {
                    Circle()
                        .fill(showChart ? Color.green : Color.red)
                        .shadow(color: Color.gray, radius: 5, x: 2, y: 2)
                    Text("Charts")
                        .foregroundColor(Color.primary)
                    
                }.frame(width: 150, height: 50)
            }
            
            ScrollView {
                LazyVGrid (
                    columns: columns, spacing: 50
                ) {
                    ForEach(0 ..< 25) { item in
                        ZStack {
                            Rectangle()
                                .fill(Color.red)
                                .cornerRadius(15)
                            
                            VStack {
                                SeparateComponent()
                                if showChart {
                                    Rectangle()
                                        .fill(Color.green)
                                        .frame(height: 200)
                                }
                            }
                        }
                    }
                }
                .id(UUID()) //<-- Here
            }
        }
        
    }
}

struct SeparateComponent : View {
    @State var isAnimating : Bool = false
    
    var body: some View {
        HStack {
            Text("Hello, World!")
            Spacer()
            Image(systemName: "bell.fill")
                .foregroundColor(Color.yellow)
                .opacity(self.isAnimating ? 1 : 0)
                .animation(Animation.easeInOut(duration: 0.66).repeatForever(autoreverses: false))
                .onAppear{
                    self.isAnimating = true
                }
        }
        .padding(50)
    }
}

结构FlashingBellLazyVGrid:视图{
@状态变量showChart=true
let columns=[GridItem(.adaptive(最小值:300),间距:50,对齐方式:。居中)]
var body:一些观点{
VStack{
按钮(操作:{
showChart.toggle()
}) {
VStack{
圈()
.fill(显示图?颜色。绿色:颜色。红色)
.阴影(颜色:颜色.灰色,半径:5,x:2,y:2)
文本(“图表”)
.foregroundColor(颜色.primary)
}.框架(宽度:150,高度:50)
}
滚动视图{
懒散网格(
列:列,间距:50
) {
ForEach(0..<25){
ZStack{
矩形()
.填充(颜色.红色)
.转弯半径(15)
VStack{
分离组件()
如果显示图{
矩形()
.填充(颜色.绿色)
.框架(高度:200)
}
}
}
}
}

.id(UUID())//包含一个可能很好,因为该行为不是仅由您包含的代码复制的。谢谢明天发送。您将如何使systemIcon原地闪烁。动画似乎总是从某个边缘过渡到某个位置。如何使其原地闪烁,而首先忽略边界父视图?@jnpdx看一看在上面的这个例子中。它正在做一件奇怪的事情。奇怪的是,在SwiftUI中,在更复杂的视图中闪烁图标似乎会被破坏。一旦您更改了父帧,它就会出错。如果您有一个固定的帧,它就可以了。所以我的解决方案不适用于您?