Last active
June 20, 2020 13:56
-
-
Save dduan/ea3bf501d548e6b194dd7f637bf3ba54 to your computer and use it in GitHub Desktop.
Twitter's voice tweet UI has an interesting animation on iOS. This is an attempt to recreate that animation with SwiftUI. Looks like this https://youtu.be/I6XZzIgWYAQ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ChaoticPhoto: View { | |
let image: Image | |
let radius: CGFloat | |
@Binding var activated: Bool | |
@State var scale: CGFloat = 1 | |
var body: some View { | |
image | |
.resizable() | |
.frame(width: radius, height: radius) | |
.mask(Circle()) | |
.scaleEffect(activated ? scale : 1) | |
.onAppear { | |
Timer.scheduledTimer( | |
withTimeInterval: 0.05, | |
repeats: true | |
) { _ in | |
self.scale = CGFloat.random(in: 1...1.1) | |
} | |
} | |
} | |
} | |
struct ChaoticCircle: View { | |
let radius: CGFloat | |
@Binding var activated: Bool | |
@State var scale: CGFloat = 1 | |
@State var offSet: CGFloat = 0 | |
@State var xDirection: CGFloat = 0 | |
@State var yDirection: CGFloat = 0 | |
var body: some View { | |
Circle() | |
.fill(Color.white.opacity(0.15)) | |
.frame(width: radius, height: radius) | |
.offset( | |
x: activated ? xDirection * offSet : 0, | |
y: activated ? yDirection * offSet : 0 | |
) | |
.scaleEffect(activated ? scale : 1) | |
.onAppear(perform: { | |
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in | |
withAnimation(Animation.easeInOut(duration: 0.1)) { | |
self.xDirection = [CGFloat(0.0), CGFloat(1), CGFloat(-1)].randomElement() ?? CGFloat(0) | |
self.yDirection = [CGFloat(0.0), CGFloat(1), CGFloat(-1)].randomElement() ?? CGFloat(0) | |
self.offSet = CGFloat.random(in: 5...8) | |
self.scale = CGFloat.random(in: CGFloat(1.2)...CGFloat(1.4)) | |
} | |
} | |
}) | |
} | |
} | |
struct ActivateButton: View { | |
@Binding var activated: Bool | |
var body: some View { | |
Button(action: { | |
self.activated.toggle() | |
}) { | |
Text(activated ? "Stop" : "Speak") | |
.frame(width: 200, height: 44) | |
.foregroundColor(Color.white) | |
.background( | |
RoundedRectangle(cornerRadius: 10) | |
.foregroundColor(Color("main")) | |
) | |
} | |
.shadow(color: Color.white, radius: 5) | |
} | |
} | |
struct ContentView: View { | |
@State var activated = false | |
var body: some View { | |
VStack { | |
Spacer() | |
ZStack { | |
ChaoticCircle(radius: 100, activated: self.$activated) | |
ChaoticCircle(radius: 100, activated: self.$activated) | |
ChaoticCircle(radius: 100, activated: self.$activated) | |
ChaoticPhoto(image: Image("profile photo"), radius: 98, activated: self.$activated) | |
} | |
Spacer() | |
ActivateButton(activated: $activated) | |
Spacer() | |
} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background(Color("main").saturation(0.6)) | |
.edgesIgnoringSafeArea(.all) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment