Created
January 9, 2022 20:36
-
-
Save fespinoza/c54e111f5cc74f7da727b3439153f972 to your computer and use it in GitHub Desktop.
Shimmer Animation Over Content
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 | |
/* | |
## Animated highlight over redacted code | |
To actually try to get a loading shimmer animation on redacted content | |
Interesting concepts: | |
- overlay + `.blendMode` | |
- Infinite Animations | |
- Stopping animations | |
Sources: | |
- https://www.swiftkickmobile.com/creating-a-repeating-animation-in-swiftui/ | |
- https://stackoverflow.com/questions/59133826/swiftui-stop-an-animation-that-repeats-forever | |
*/ | |
struct RedactedAnimationExperimentView: View { | |
@State var offsetX: CGFloat = 0 | |
@State var duration: CGFloat = 1.5 | |
@State var animationStarted: Bool = false | |
@State var stopAnimation: Bool = false | |
// var animation: Animation? = Animation.easeInOut.repeatForever(autoreverses: false) | |
var body: some View { | |
VStack { | |
SampleContentView() | |
.redacted(reason: .placeholder) | |
.overlay(overlayContent) | |
Circle() | |
.foregroundColor(Color.gray) | |
.frame(width: 200, height: 200) | |
.overlay(overlayContent) | |
.clipped() | |
Spacer() | |
form | |
} | |
} | |
var overlayContent: some View { | |
GeometryReader { proxy in | |
Color | |
.white | |
.opacity(0.5) | |
// .blur(radius: 5) | |
.frame(width: proxy.size.width * 0.3) | |
.offset(x: proxy.size.width * offsetX, y: 0) | |
.blendMode(.lighten) | |
} | |
} | |
var form: some View { | |
VStack { | |
Text("Offset: ") + Text(offsetX, format: .number) | |
Text("Duration: ") + Text(duration, format: .number) | |
Slider(value: $offsetX) | |
.padding() | |
Slider(value: $duration, in: (0.1...CGFloat(3.0))) | |
.padding() | |
Button("Animate", action: animateOverlay) | |
} | |
} | |
let delta: CGFloat = 5 | |
func animateOverlay() { | |
var animation = Animation.easeInOut(duration: duration) | |
if animationStarted { | |
// animationRunningFromBefore = false | |
// no repeat forever | |
animationStarted = false | |
} else { | |
animation = animation.repeatForever(autoreverses: false) | |
animationStarted = true | |
} | |
withAnimation(animation) { | |
offsetX = offsetX > 1 ? 0 : offsetX + delta | |
} | |
} | |
} | |
extension RedactedAnimationExperimentView { | |
struct SampleContentView: View { | |
var body: some View { | |
VStack { | |
Image("sampleAvatar") | |
.resizable() | |
.frame(width: 80, height: 80) | |
.clipShape(Circle()) | |
.clipped() | |
Text("Felipe Espinoza") | |
.font(.title) | |
Divider() | |
HStack { | |
number(title: "Followers", value: "20") | |
Divider().frame(height: 80) | |
number(title: "Following", value: "10") | |
} | |
Divider() | |
// Spacer() | |
} | |
} | |
@ViewBuilder func number(title: String, value: String) -> some View { | |
Spacer() | |
VStack(spacing: 8) { | |
Text(title).font(.subheadline) | |
Text(value).font(.title2) | |
} | |
Spacer() | |
} | |
} | |
} | |
struct RedactedAnimationExperimentView_Previews: PreviewProvider { | |
static var previews: some View { | |
RedactedAnimationExperimentView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment