Created
July 9, 2020 20:38
-
-
Save rr-codes/439d4dbf265448b970596c7c0d983414 to your computer and use it in GitHub Desktop.
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
| // | |
| // Playground.swift | |
| // Hourglass | |
| // | |
| // Created by Richard Robinson on 2020-07-06. | |
| // | |
| import Foundation | |
| import SwiftUI | |
| import PlaygroundSupport | |
| extension AnyTransition { | |
| static var rotate: AnyTransition { get { | |
| AnyTransition.modifier(active: RotateTransition(percent: 0), identity: RotateTransition(percent: 1)) | |
| } | |
| } | |
| } | |
| struct RotateTransition: GeometryEffect { | |
| var percent: Double | |
| var animatableData: Double { | |
| get { percent } | |
| set { percent = newValue } | |
| } | |
| func effectValue(size: CGSize) -> ProjectionTransform { | |
| let rotationPercent = percent | |
| let a = CGFloat(Angle(degrees: 170 * (1-rotationPercent)).radians) | |
| var transform3d = CATransform3DIdentity; | |
| transform3d.m34 = -1/max(size.width, size.height) | |
| transform3d = CATransform3DRotate(transform3d, a, 0, 1, 0) | |
| transform3d = CATransform3DTranslate(transform3d, -size.width/2.0, -size.height/2.0, 0) | |
| let affineTransform1 = ProjectionTransform(CGAffineTransform(translationX: size.width/2.0, y: size.height / 2.0)) | |
| let affineTransform2 = ProjectionTransform(CGAffineTransform(scaleX: CGFloat(percent * 2), y: CGFloat(percent * 2))) | |
| if percent <= 0.5 { | |
| return ProjectionTransform(transform3d).concatenating(affineTransform2).concatenating(affineTransform1) | |
| } else { | |
| return ProjectionTransform(transform3d).concatenating(affineTransform1) | |
| } | |
| } | |
| } | |
| struct ContentView : View { | |
| @State var show = false | |
| @State var selectedColor: Color? = nil | |
| @Namespace var namespace | |
| let columns: [GridItem] = Array(repeating: GridItem(.flexible(), spacing: 0), count: 2) | |
| let colors: [Color] = [.red, .blue, .green, .purple, .pink, .yellow] | |
| var body: some View { | |
| ZStack { | |
| LazyVGrid(columns: columns) { | |
| ForEach(colors, id: \.self) { color in | |
| color | |
| .frame(width: 200, height: 200) | |
| .onTapGesture { | |
| self.selectedColor = color | |
| DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { | |
| self.show = true | |
| } | |
| } | |
| .zIndex(self.selectedColor == color ? 5 : 0) | |
| .animation(.spring()) | |
| .transition(.rotate) | |
| .matchedGeometryEffect(id: "\(color.hashValue)", in: namespace, isSource: false) | |
| } | |
| } | |
| if show { | |
| Color.black | |
| .frame(width: 300, height: 300, alignment: .center) | |
| .zIndex(2) | |
| .animation(.spring()) | |
| .transition(.rotate) | |
| .matchedGeometryEffect(id: "\(selectedColor?.hashValue ?? -1)", in: namespace, isSource: true) | |
| } | |
| } | |
| } | |
| } | |
| PlaygroundPage.current.setLiveView( | |
| ContentView().frame(width: 450, height: 650) | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment