1

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.

2 Answers 2

2

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)
            }
        }
 
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

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()
        }
    }
}

6 Comments

when i add your animation, the scroll goes to the last circle, but it cuts off part of it on the side, do you know how I could fix this?
on which side does it cut off?
nevermind it was a padding issue, thank you for your response anyway! :)
puuh ... I'm glad ;)
although I will say that the scroll is a little bit glitchy, almost like the scroll is being "forced" (kind of like it rubber bands). any idea on how to fix that?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.