Add Animations to Foreach Loop Elements (Swiftui)

Add animations to ForEach loop elements (SwiftUI)

It looks like this problem is still up to day (Xcode 11.4), because by just copy-pasting the observed effect is the same. So, there are a couple of problems here: first, it needs to setup combination of animation and transition correctly; and, second, the ForEach container have to know which exactly item is removed, so items must be identified, instead of indices, which are anonymous.

As a result we have the following effect (transition/animation can be others):

demo

struct TestAnimationInStack: View {
@State var ContentArray = ["A","B","C", "D", "E", "F", "G", "I", "J"]
var body: some View {
ScrollView{
VStack{
ForEach(Array(ContentArray.enumerated()), id: \.element){ (i, item) in // << 1) !
ZStack{
// Object
Text(item)
.frame(width:100,height:100)
.background(Color.gray)
.cornerRadius(20)
.padding()
//Delete button
Button(action: {
withAnimation { () -> () in // << 2) !!
self.ContentArray.remove(at: i)
}
}){
Text("✕")
.foregroundColor(.white)
.frame(width:40,height:40)
.background(Color.red)
.cornerRadius(100)
}.offset(x:40,y:-40)
}.transition(AnyTransition.scale) // << 3) !!!
}
}
}
}
}

How to animate the removal of a view created with a ForEach loop getting its data from an ObservableObject in SwiftUI

It is not clear which effect do you try to achieve, but on remove you should animate not view internals, but view itself, ie. in parent, because view remove there and as-a-whole.

Something like (just direction where to experiment):

var body: some View {
ZStack {
ForEach(tagModel.tags, id: \.self) { label in
TagView(label: label)
.transition(.move(edge: .leading)) // << here !! (maybe asymmetric needed)
}
.onReceive(timer) { _ in
self.tagModel.addNextTag()
if tagModel.tags.count > 3 {
self.tagModel.removeOldestTag()
}
}
}
.animation(Animation.easeInOut(duration: 1)) // << here !! (parent animates subview removing)

Insert, update and delete animations with ForEach in SwiftUI

Luckily this is actually really easy to do. Simply remove .animation(.spring()) on your Row, and wrap any changes in withAnimation(.spring()) { ... }.

So the add button will look like this:

private var AddButton: some View {
Button(action: {
withAnimation(.spring()) {
self.items.insert(Item(name: "Jeff"), at: 0)
}
}) {
Text("Add")
}
}

and your Row will look like this:

struct Row: View {

@State var name: String

var body: some View {
HStack {
Text(name)
Spacer()
}
.padding()
.transition(.move(edge: .leading))
}
}

How to add a modifier to any specific buttons inside a ForEach loop for an array of buttons in SwiftUI?

import SwiftUI

struct AnimatedListView: View {
var body: some View {
VStack{
ForEach(0..<5) { num in
//The content of the ForEach goes into its own View
AnimatedButtonView(num: num)
}
}
}
}
struct AnimatedButtonView: View {
//This creates an @State for each element of the ForEach
@State private var rotationDegree = 0.0
//Pass the loops data as a parameter
let num: Int
var body: some View {
Button {
withAnimation {
rotationDegree += 360
}
} label: {
Image(systemName: "person")
Text(num.description)
}
.rotation3DEffect((.degrees(rotationDegree)), axis: (x: 0, y: 1, z: 0))
}
}
struct AnimatedListView_Previews: PreviewProvider {
static var previews: some View {
AnimatedListView()
}
}

SwiftUI - How to animate components corresponding to array elements?

a version with automatic scroll to the last circle:

struct myItem: Identifiable, Equatable {
let id = UUID()
var size: CGFloat
}

struct ContentView: View {

@State private var myArr: [myItem] = [
myItem(size: 10),
myItem(size: 40),
myItem(size: 30)
]

var body: some View {

ScrollViewReader { scrollProxy in
VStack(alignment: .leading) {
Spacer()

ScrollView(.horizontal) {
HStack {
ForEach(myArr) { item in
Circle()
.id(item.id)
.frame(width: item.size, height: item.size)
.transition(.scale)
}
}
}
.animation(.easeInOut(duration: 1), value: myArr)

Spacer()

Button("Add One") {
let new = myItem(size: CGFloat.random(in: 10...100))
myArr.append(new)
}

.onChange(of: myArr) { _ in
withAnimation {
scrollProxy.scrollTo(myArr.last!.id, anchor: .trailing)
}
}

.frame(maxWidth: .infinity, alignment: .center)
}
.padding()
}
}
}

How can I animate individual rows in SwiftUI List?

The key seems to be using the indices from the ForEach loop to set the times at which the animations appear.

Below is the code. The toggle switch just resets the state to show the animation:

struct GuideListView: View {
let data = ["One", "Two", "Three", "Four"]
@State var showListItems = false
@State var animationDelay = 0.5
// definitions of viewRouter, data etc.

var body: some View {

VStack {

// other items, navLink etc.
Toggle("Show List Items", isOn: $showListItems)

List {

ForEach(data.indices) { index in

Button(action: {
// navigation action
}, label: {
Text(data[index])
})
.opacity(showListItems ? 1 : 0)
.animation(Animation.easeOut(duration: 0.6).delay(animationDelay * Double(index)), value: showListItems)

} //: ForEach

} //: List

} //: VStack
}
}


Related Topics



Leave a reply



Submit