I have an HStack of circles in SwiftUI, and the number of circles is determined based on the length of an array, like this:
@State var myArr = [...]
...
ScrollView(.horizontal) {
HStack {
ForEach(myArr) { item in
Circle()
//.frame(...)
//.animation(...) I tried this, it didn't work
}
}
}
Then I have a button that appends an element to this array, effectively adding a circle to the view:
Button {
myArr.append(...)
} label: {
...
}
The button works as intended, however, the new circle that is added to the view appears very abruptly, and seems choppy. How can I animate this in any way? Perhaps it slides in from the side, or grows from a very small circle to its normal size.
CodePudding user response:
You are missing transition, here is what you looking:
struct ContentView: View {
@State private var array: [Int] = Array(0...2)
var body: some View {
ScrollView(.horizontal) {
HStack {
ForEach(array, id:\.self) { item in
Circle()
.frame(width: 50, height: 50)
.transition(AnyTransition.scale)
}
}
}
.animation(.default, value: array.count)
Button("add new circle") {
array.append(array.count)
}
Button("remove a circle") {
if array.count > 0 {
array.remove(at: array.count - 1)
}
}
}
}
CodePudding user response:
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()
}
}
}