In the twitter app, when you tap on the share button, and then tap the Copy Link button, a view that says "Copied to clipboard" would move into the screen from the top. It stays on the top of the screen for about 1 second and then it moves back up the screen and disappears. Like this:

My goal is to create the same effect in my SwiftUI app whenever I double tap on a text view. But I just can't figure out how to achieve this effect. This is the best I could get:
import SwiftUI
struct ContentView: View {
@State private var copied = false
var body: some View {
GeometryReader { gr in
ZStack {
if copied {
Text("Copied to clipboard")
.padding()
.background(Color.blue.cornerRadius(20))
.position(x: gr.frame(in: .local).midX)
.transition(.move(edge: .top))
.animation(Animation.easeInOut(duration: 2).repeatCount(2))
}
VStack {
Text("Copy")
.onTapGesture(count: 2) {
self.copied.toggle()
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
struct ContentView: View {
@State private var copied = false {
didSet {
if copied == true {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
copied = false
}
}
}
}
}
var body: some View {
GeometryReader { geo in
ZStack {
if copied {
Text("Copied to clipboard")
.padding()
.background(Color.blue.cornerRadius(20))
.position(x: geo.frame(in: .local).width/2)
.transition(.move(edge: .top))
.padding(.top)
.animation(Animation.easeInOut(duration: 1))
}
VStack {
Text("Copy")
.onTapGesture(count: 2) {
withAnimation {
copied = true
}
}
}
}.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
Result:

you can change the state back to false inside didSet
struct ContentView: View {
@State private var copied = false {
didSet {
if copied == true {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
copied = false
}
}
}
}
}
var body: some View {
GeometryReader { gr in
ZStack {
if copied {
Text("Copied to clipboard")
.padding()
.background(Color.blue.cornerRadius(20))
.position(x: gr.frame(in: .local).midX)
.transition(.move(edge: .top))
.animation(Animation.easeInOut(duration: 1))
.padding()
}
VStack {
Text("Copy")
.onTapGesture(count: 2) {
withAnimation {
copied = true
}
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With