Created
January 21, 2025 14:36
-
-
Save LidorFadida/4ba7f9e8c8f5ef0707948b932c035b22 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
| // | |
| // Neumorphism.swift | |
| // Neumorphism | |
| // | |
| // Created by Lidor Fadida on 21/01/2025. | |
| // | |
| struct NeumorphismPyramidView: View { | |
| @State private var animate: Bool = false | |
| @State private var animationProperties: [(Double, Double)] = Constants.range.map { index in | |
| (0.0, Double(index) * 0.1) | |
| } | |
| private struct Constants { | |
| static let range = (0..<9) | |
| static let animationDuration: TimeInterval = 0.3 | |
| } | |
| var body: some View { | |
| GeometryReader { proxy in | |
| ZStack { | |
| neumorphicSteps(proxy: proxy) | |
| } | |
| .frame(width: proxy.size.width, height: proxy.size.height) | |
| } | |
| .contentShape( | |
| Rectangle() | |
| ) | |
| .onTapGesture(perform: didTapGeometryReader) | |
| } | |
| private func didTapGeometryReader() { | |
| animate.toggle() | |
| animationProperties = Constants.range.map { index in | |
| let opacity = animate ? 1.0 : 0.0 | |
| let value = animate ? 1.0 - Double(index) * 0.1 : Double(index) * 0.1 | |
| return (opacity, value) | |
| } | |
| } | |
| private func neumorphicSteps(proxy: GeometryProxy) -> some View { | |
| ForEach(animationProperties.indices, id: \.self) { index in | |
| let index = animate ? index : (animationProperties.count - 1) - index | |
| let (opacity, sizeMultiplier) = animationProperties[index] | |
| let size = CGSize( | |
| width: proxy.size.width * sizeMultiplier, | |
| height: proxy.size.height * sizeMultiplier | |
| ) | |
| let delay = CGFloat(index) * 0.3 | |
| makeStep(opacity: opacity, size: size) | |
| .animation( | |
| .easeInOut(duration: Constants.animationDuration).delay(delay), | |
| value: animate | |
| ) | |
| } | |
| } | |
| @ViewBuilder | |
| private func makeStep(opacity: Double, size: CGSize) -> some View { | |
| let cornerRadius = size.width * 0.1 | |
| let fillColor = Color.lightGray | |
| let shadowRadius = 8.0 | |
| ZStack { | |
| RoundedRectangle(cornerRadius: cornerRadius) | |
| .fill(fillColor) | |
| .opacity(opacity) | |
| .frame(width: size.width, height: size.height) | |
| .shadow(color: Color.white.opacity(0.8), radius: shadowRadius, x: -shadowRadius, y: -shadowRadius) | |
| .shadow(color: Color.black.opacity(0.2), radius: shadowRadius, x: shadowRadius, y: shadowRadius) | |
| RoundedRectangle(cornerRadius: cornerRadius) | |
| .fill(fillColor) | |
| .frame(width: size.width, height: size.height) | |
| } | |
| } | |
| } | |
| extension Color { | |
| static let lightGray = Color( ///Your favorite color | |
| red: <#T##Double#>, | |
| green: <#T##Double#>, | |
| blue: <#T##Double#> | |
| ) | |
| } | |
| #Preview("Neumorphism") { | |
| ZStack { | |
| Color.lightGray ///Use your | |
| .ignoresSafeArea() | |
| NeumorphismPyramidView() | |
| .padding() | |
| } | |
| .frame(maxWidth: .infinity, maxHeight: .infinity) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment