0

I am trying to make the yellow views disappear from bottom and top with a nice and smooth animation. (slide/move to top/bottom + fadding and keep the middle view taking the whole space) This is my current state, and it is everything but smooth and nice haha. but it works.

import SwiftUI

struct ContentView: View {
    @State var isInterfaceHidden: Bool = false

    var body: some View {
        VStack(spacing: 0, content: {
            if !isInterfaceHidden {
                Rectangle()
                    .id("animation")
                    .foregroundColor(Color.yellow)
                    .frame(height: 40)
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity).animation(.linear))
            }
            Rectangle()
                .id("animation2")
                .foregroundColor(Color.red)
                .transition(AnyTransition.opacity.animation(Animation.linear))
                /// We make sure it won't cover the top and bottom view.
                .zIndex(-1)
                .background(Color.red)
                .onTapGesture(perform: {
                    DispatchQueue.main.async {
                        self.isInterfaceHidden.toggle()
                    }
                })
            if !isInterfaceHidden {
                Rectangle()
                    .id("animation3")
                    .foregroundColor(Color.yellow)
                    .frame(height: 80)
                    .transition(AnyTransition.move(edge: .bottom).combined(with: .opacity).animation(.linear))
            }
        })
        .navigationBarTitle("")
        .navigationBarHidden(true)
    }
}

Current animation:

current animation

Edit3: Thanks to @Andrew I was able to progress in a better state. But now I have a sort of jerky animation. Any thoughts?

Oleg G.
  • 550
  • 5
  • 25
  • If you try to leave both yellow rectangles fixed and move the red rectangle? In that way you'll loose the removal of the yellow rectangle, that is what is causing you troubles – Carlos Maria Caraccia Sep 17 '20 at 21:33

3 Answers3

2

I may have found a solution for you:

import SwiftUI

struct ContentView: View {
    @State var isInterfaceHidden: Bool = false

    var body: some View {
        VStack(spacing: 0, content: {
            if !isInterfaceHidden {
                Rectangle()
                    .id("animation")
                    .foregroundColor(Color.yellow)
                    .frame(height: 40)
                    .transition(.topViewTransition)
            }
            Rectangle()
                .id("animation2")
                .foregroundColor(Color.red)
                /// We make sure it won't cover the top and bottom view.
                .zIndex(-1)
                .background(Color.red)
                .onTapGesture(perform: {
                    DispatchQueue.main.async {
                        self.isInterfaceHidden.toggle()
                    }
                })
            if !isInterfaceHidden {
                Rectangle()
                    .id("animation3")
                    .foregroundColor(Color.yellow)
                    .frame(height: 80)
                    .transition(.bottomViewTransition)
            }
        })
        .navigationBarTitle("")
        .navigationBarHidden(true)
        .animation(.easeInOut)
    }
}

extension AnyTransition {

    static var topViewTransition: AnyTransition {
        let transition = AnyTransition.move(edge: .top)
            .combined(with: .opacity)
        return transition
    }

    static var bottomViewTransition: AnyTransition {
        let transition = AnyTransition.move(edge: .bottom)
            .combined(with: .opacity)
        return transition
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
1

Simply set Z index for the both of your yellow views anything higher than the default value of 1.0. This way SwiftUI will make sure they won't be covered by the red view.

The modifier to do that is .zIndex()

Andrew
  • 344
  • 3
  • 10
  • I guess `zIndex(-1)` on the middle view works fine too right? – Oleg G. Sep 17 '20 at 21:35
  • Yep, works like that too. Thank you so much @Andrew! – Oleg G. Sep 17 '20 at 21:36
  • On the way, I wanted to add an additional transition with fading. It seems that `.combined(with: .opacity)` breaks the animation, do you have an idea for how to fix that one too? – Oleg G. Sep 17 '20 at 21:40
-1

A simpler solution

struct Test: View {

@State private var isHiding = false

var body: some View {
    ZStack {
        Rectangle()
            .foregroundColor(.yellow)
            .frame(width: 200, height: 100)
        Rectangle()
            .foregroundColor(.red)
            .frame(width: 200, height: isHiding ? 100 : 80)
            .onTapGesture {
                withAnimation {
                    self.isHiding.toggle()
                }
        }
    }
}

}

  • not sure to understand the relation between your code and the end goal of the post :/ I am trying to have a top/middle/bottom view with the top/bottom that can hide by pressing the middle one. Use Case: Audio Player - with the middle being the picture of whatever, the top contain the name of the music etc. and the Bottom contains the play/pause button etc. – Oleg G. Sep 17 '20 at 21:55
  • Ok! Thought another use – Carlos Maria Caraccia Sep 17 '20 at 21:58
  • Thank you for trying to help me! I updated the original post, hopefully it is more readable :D – Oleg G. Sep 18 '20 at 05:19