Animate a view from the side in SwiftUI
You can use a .transition()
modifier on the circle, and the .blur()
modifier on the other views that are not the circle, combined with .animation()
.
Also, on the views that are "not circle", you need to add another modifier: .allowsHitTesting()
, to avoid having the user interacting with the views that are blurred.
Remember that, when you trigger someState
, you must use the .withAnimation()
closure, otherwise the circle will not slide in.
Here's how the code looks like (I added some things on the ZStack
just to provide an example). I also made the someState
variable a boolean for convenience in the example, but in your case you can just check for the enum.
CircleView
struct CircleView: View {
@Binding var someState: Bool
var body: some View {
Circle()
.foregroundColor(.red)
.overlay(Text("All is blur"))
.onTapGesture {
someState.toggle()
}
// These modifiers are necessary to animate the circle
.transition(.move(edge: .trailing))
.animation(.easeInOut, value: someState)
}
}
Another view
@State private var someState = false
var body: some View {
GeometryReader { geo in
ZStack {
VStack {
Button {
// Without this closure, the circle does not slide in
withAnimation {
someState.toggle()
}
} label: {
Text("Show circle")
}
.padding()
Spacer()
Text("Bottom")
.padding()
}
// This modifier blurs the view that is not the circle
.blur(radius: someState ? 5 : 0)
// This modifier animates the blur effect
.animation(.easeInOut, value: someState)
// This is necessary to block the view from accepting user taps
// when the circle is showing
.allowsHitTesting(!someState)
if someState {
CircleView(someState: $someState)
// Stop the circle half-way
.offset(x: UIScreen.main.bounds.width / 2, y: 0)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.ignoresSafeArea()
}
}
SwiftUI Animation Slide In and Out
Move conditional part into container and add animation to container, so it will animate content, like
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .center) {
self.parentView()
VStack { // << here !!
if(self.isShowing == true){
VStack {
Text("This is a test view\n")
Button(action: {
self.isShowing.toggle()
}) {
Text("Close")
}
}
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Color(UIColor.systemBackground))
.transition(.move(edge: self.isShowing ? .trailing : .leading))
}
}.animation(Animation.easeInOut(duration: 1.0)) // << here !!
}
}
}
How to support Slide In Out animation in SwiftUI?
Try this:
import SwiftUI
struct NotificationView: View {
@State private var showNotification = false
var body: some View {
ZStack {
SuccessNotification()
.offset(y: showNotification ? (-UIScreen.main.bounds.height / 3) : -UIScreen.main.bounds.height)
.animation(.interpolatingSpring(mass: 1.0, stiffness: 100.0, damping: 10, initialVelocity: 0), value: showNotification)
Button("Press me") { showNotification.toggle() }
}
}
}
struct NotificationView_Previews: PreviewProvider {
static var previews: some View {
NotificationView()
}
}
struct SuccessNotification: View {
var body: some View {
Text("Success")
.padding()
.foregroundColor(.white)
.frame(width: UIScreen.main.bounds.width - 10, height: 100)
.background(.green, in: RoundedRectangle(cornerRadius: 20))
}
}
'animation' was deprecated in iOS 15.0
So just use the @State that changes the animation as the value :
@State private var showNotification = false
.animation(.linear, value: showNotification)
SwiftUI: Animate offset to slide in from off screen
It can be done just with transition, like
Tested with Xcode 13.3 / iOS 15.4
struct ContentView: View {
@State var isShowingBanner = true
var body: some View {
VStack {
VStack {
Spacer()
if isShowingBanner {
BannerView()
.transition(.move(edge: .bottom)) // << here !!
}
}
// >> empty container should not shrink !!
.frame(maxWidth: .infinity, maxHeight: .infinity)
.border(Color.black, width: 1.0)
.clipped()
Spacer()
Button("Toggle Banner") {
withAnimation {
isShowingBanner.toggle()
}
}
}
.padding()
}
}
SwiftUI: Pattern matching causes view to animate incorrectly
When the binding changes, the ChildView changes two things: Show "foo" which hadn't been there before, and change the offset of anything else to 0.
So animation will only work on what has been there before. i.e. "Bar".
But you can change the value of elements, that are already there:
struct ChildView: View {
@Binding var foo: String?
var body: some View {
HStack {
Text(foo ?? "")
Spacer()
Text("Bar")
}
.offset(y: foo != nil ? 0 : UIScreen.main.bounds.height)
}
}
Related Topics
How to Call Initializer for Subclass of Generic Type
Difference Between Dispatchqueue Types in Swift
How to Make a Uiview Focusable Using the Focus Engine on Apple Tv
List All Available Audio Devices
Uisplitviewcontroller in Portrait on iPhone Always Show Master and Detail in iOS 8
Update Core Data Object Order - Not Working
Get an Error When Trying to Get All the Photos from Phassetcollection.Fetchassetcollections
How to Add Initializers in Extensions to Existing Uikit Classes Such as Uicolor
.Dynamictype Is Deprecated. Use 'Type(Of ...)' Instead
Need Self to Set All Constants of a Swift Class in Init
Why Do Servicesubscribercellularproviders Return Nil? (In iOS 12)
How to Automatically Reflect Coredata+Icloud Changes in Swiftui View
How to Alloc/Dealloc Unsafe Pointers in Swift
Swift .Uppercasestring or .Lowercasestring Property Replacement