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