1

I am switching from UIKit to SwiftUI and still struggle to understand some parts of it, especially the transitions between views.

I have a situation where is displayed on screen a view controller with a list, say ElementsListViewController(), and when tapping an element I want to display a modal with a custom UI/animation: the opaque overlay would appear with an animation of the alpha value while the white modal "sheet" would appear from bottom to top.

Here is what it looks like:

enter image description here

With UIKit, I would use UIViewControllerAnimatedTransitioning to do that.

Now I would like to do the same with SwiftUI, but I am lost with what to do exactly here.

I have this so far:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ElementsList()
        }
    }
}

struct ElementsList: View {
    @State var elements: [String] = (0..<100).map { "Element #\($0)" }

    var body: some View {
        List(elements, id: \.self) {
            Text($0)
                .onTapGesture {
                    // what to do here to display ModalView as I want to?
                }
        }
        .listStyle(PlainListStyle())
    }
}

struct ModalView: View {
    var body: some View {
        ZStack {
            Color.black.opacity(0.8)
            Color.white
                .cornerRadius(20.0)
                .padding(.top, 150)
        }
        .ignoresSafeArea()
    }
}

What is my best option here? Thank you for your help

Ken White
  • 123,280
  • 14
  • 225
  • 444
Another Dude
  • 1,204
  • 4
  • 15
  • 33
  • Make your own and/or use UIViewControllerRepresentable. It seems harder than it is but I’d you are familiar with UIKit it is only a few extra lines to make it work with SwiftUI [see here for starter](https://stackoverflow.com/questions/67982691/using-uisheetpresentationcontroller-in-swiftui/67994468#67994468) – lorem ipsum May 17 '22 at 17:46
  • @loremipsum Thank you for your answer! I know I could easily do it with a UIViewControllerRepresentable, but my intention is to do it in a way which is 100% SwiftUI if that is possible, in order to understand it as much as I can! – Another Dude May 17 '22 at 18:15
  • it can't be done with the standard `ViewModifier`s. You can create your own as you are plus a custom [ViewModifier](https://developer.apple.com/documentation/swiftui/viewmodifier) and a `Binding`but you lose the swiping, especially the swiping with a `List`. A `DragGesture` will interfere with the dragging of a `List` or a `ScrollView` – lorem ipsum May 17 '22 at 18:42

1 Answers1

1

Well there is no built-in such flexibility say with standard .sheet, but it can be implemented custom very fast.

Here is simple demo (Xcode 13.3 / iOS 15.4)

demo

Main part:

struct ElementsList: View {
// ...
        ModalView(isPresented: $isModal) {
            List(elements, id: \.self) {


struct ModalView<V: View>: View {
    @Binding var isPresented: Bool
// ...
        ZStack {
            content()
            ZStack {
                VStack {
                    if isPresented {
                        Color.black.opacity(0.8)
                            .transition(.opacity)
                    }
                }.animation(.easeInOut(duration: 0.25), value: isPresented)


Complete test code in project is here

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Hi @Asperi and thank you very much for your answer! It works perfectly fine, however I am a bit puzzled by the fact that the ModalView is encapsulating the List... I mean, what option would you recommend doing if I had to display a different modal for each row of the list? – Another Dude May 18 '22 at 07:15
  • 1
    Make it as view modifier, add property for selection/item, callback block, own modal view model, etc. There might be many approaches to inject additional dependencies. Here is just UI concept as asked. – Asperi May 18 '22 at 07:32