Say I have this view:
struct CircleView: View {
var body: some View {
Circle()
}
}
In another view, I have something like this:
var body: some View {
GeometryReader { geo in
ZStack {
//some other views
if someState == .showCircle {
CircleView()
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
}
}
When someState
becomes .showCircle
, I want to have the CircleView animate in from the right side of the screen into a position where the left hemisphere is visible, so it's halfway on the screen, and dim the rest of the content in the ZStack. What's the best way to set up this kind of animation?
CodePudding user response:
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()
}
}