Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recreate twitter's copied to clipboard animation in SwiftUI

Tags:

ios

swift

swiftui

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:

enter image description here

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)
        }
    }
}
like image 364
SmoothPoop69 Avatar asked Oct 30 '25 10:10

SmoothPoop69


2 Answers

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:

enter image description here

like image 141
Harshil Patel Avatar answered Nov 01 '25 04:11

Harshil Patel


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)
        }
    }
}
like image 33
Yodagama Avatar answered Nov 01 '25 06:11

Yodagama