Home > OS >  Animate bubble with SwiftUI
Animate bubble with SwiftUI

Time:12-24

I want to make a mini game for kids that have Alphabet characters floating inside a bubble so I used text with overlay image and it's working but the problem is when I tap on the bubble I don't know how to make it disappear with animation and make the text stop on current location

struct ExtractedView: View {
    @State var BubbleAnimate = false
    @State var AlphbetArray: [String] = ["A", "B","C","D","E","F","G"]
    @State var randomNumber = Int.random(in: 0...6)
    
    var body: some View {
        Button {
            BubbleAnimate = true
            print("Hi")
        } label: {
            Text("Test Me")
        }
        .offset(x:100)

        Text(AlphbetArray[randomNumber])
                    .font(.system(size: 120))
                    .fontWeight(.bold)
                    .foregroundColor(.purple)
                    .padding()
                    .overlay {
                        
                        Image("bubble").resizable().frame(width: 130.0, height: 130.0).scaledToFit()
                    }
                    .animation(.linear(duration: 5).repeatForever(autoreverses: false), value: BubbleAnimate)
                .offset(y:BubbleAnimate ? -300 : 300)
                .onTapGesture {
                    print("Hello")
                    BubbleAnimate.toggle()

                    // I tried toggle but it won't work probably 
                }
    }
}

enter image description here

This is the result how can I make the bubble disappear with animation and make the letter stay for 1 second period to make more animation on it like scaling etc...

CodePudding user response:

There are a few considerations:

  • The letter will never stop in a specific place, given that it has only two positions: offset 300, or offset -300. To make it stop somewhere, the offset must have intermediate values. Solution: use a timer that modifies the offset every n milliseconds.

  • The bubble is always shown. To make it disappear, you must have a condition and a specific variable to trigger its visibility. Solution: create a variable that conditionally shows the bubble, and animate it using the .transition() modifier.

  • Variables must start with lower case letter. Just use the convention, it makes it easier to understand the code.

Here's the code:

// Don't use binary values for the offset, use absolute values
@State private var bubbleOffset = 0.0

@State private var alphabetArray: [String] = ["A", "B","C","D","E","F","G"]
@State private var randomNumber = Int.random(in: 0...6)

// Trigger the visibility of the bubble separately from the animation
@State private var showBubble = false

let maxOffset =  300.0
let minOffset = -300.0

// Use a timer to change the offset
let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()

var body: some View {
    
    VStack {
        Button {
            
            // The button starts the animation; in this case,
            // the animation happens only when the bubble is
            // visible, but it does not have to be like that
            showBubble = true
            print("Hi")
        } label: {
            Text("Test Me")
        }
        .offset(x:100)
        
            Text(alphabetArray[randomNumber])
                .font(.system(size: 120))
                .fontWeight(.bold)
                .foregroundColor(.purple)
                .padding()
                .overlay {
                    
                    // Show the bubble conditionally
                    if showBubble {
                        Image(systemName: "bubble.left").resizable().frame(width: 130.0, height: 130.0).scaledToFit()
                        
                            // This transition will animate the disappearance of the bubble
                            .transition(.opacity)
                    }
                    
                }
        
                // Absolute offset
                .offset(y: bubbleOffset)
                .onTapGesture {
                    withAnimation {
                        print("Hello")
                        
                        // Trigger the disappearance of the bubble
                        showBubble = false
                    }
                }
        
                .onReceive(timer) { _ in

                    // In this case,
                    // the animation happens only when the bubble is
                    // visible, but it does not have to be like that
                    if showBubble {
                        
                        // Change the offset at every emission of a new time
                        bubbleOffset -= 1
                        
                        // Handle out-of-bounds
                        if bubbleOffset < minOffset {
                            bubbleOffset = maxOffset
                        }
                    }
                }
    }
}
  • Related