46 votes

SwiftUI - Demi-modal ?

Je suis en train de recréer une Modal exactement comme Safari dans iOS13 en SwiftUI :

Voici à quoi ça ressemble :

entrez la description de l'image ici

Est-ce que quelqu'un sait si c'est possible en SwiftUI ? Je veux afficher une petite moitié de modal, avec l'option de la faire glisser en plein écran, tout comme la feuille de partage.

Tout conseil est grandement apprécié !

2voto

La réponse d'Andre Carrera est excellente et n'hésitez pas à utiliser ce guide qu'il a fourni: https://www.mozzafiller.com/posts/swiftui-slide-over-card-like-maps-stocks

J'ai modifié la structure SlideOverCard pour qu'elle utilise la hauteur réelle de l'appareil pour mesurer où la carte doit s'arrêter (vous pouvez jouer avec bounds.height pour l'ajuster à vos besoins):

struct SlideOverCard: View {

    var bounds = UIScreen.main.bounds
    @GestureState private var dragState = DragState.inactive
    @State var position = UIScreen.main.bounds.height/2

    var content: () -> Content
    var body: some View {
        let drag = DragGesture()
            .updating($dragState) { drag, state, transaction in
                state = .dragging(translation: drag.translation)
            }
            .onEnded(onDragEnded)

        return Group {
            Handle()
            self.content()
        }
        .frame(height: UIScreen.main.bounds.height)
        .background(Color.white)
        .cornerRadius(10.0)
        .shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
        .offset(y: self.position + self.dragState.translation.height)
        .animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
        .gesture(drag)
    }

    private func onDragEnded(drag: DragGesture.Value) {
        let verticalDirection = drag.predictedEndLocation.y - drag.location.y
        let cardTopEdgeLocation = self.position + drag.translation.height
        let positionAbove: CGFloat
        let positionBelow: CGFloat
        let closestPosition: CGFloat

        if cardTopEdgeLocation <= bounds.height/2 {
            positionAbove = bounds.height/7
            positionBelow = bounds.height/2
        } else {
            positionAbove = bounds.height/2
            positionBelow = bounds.height - (bounds.height/9)
        }

        if (cardTopEdgeLocation - positionAbove) < (positionBelow - cardTopEdgeLocation) {
            closestPosition = positionAbove
        } else {
            closestPosition = positionBelow
        }

        if verticalDirection > 0 {
            self.position = positionBelow
        } else if verticalDirection < 0 {
            self.position = positionAbove
        } else {
            self.position = closestPosition
        }
    }
}

enum DragState {
    case inactive
    case dragging(translation: CGSize)

    var translation: CGSize {
        switch self {
        case .inactive:
            return .zero
        case .dragging(let translation):
            return translation
        }
    }

    var isDragging: Bool {
        switch self {
        case .inactive:
            return false
        case .dragging:
            return true
        }
    }
}

2voto

SomaMan Points 2215

Je pense que presque tous les développeurs iOS qui écrivent quelque chose en SwiftUI doivent se confronter à cela. Je l'ai certainement fait, mais je pensais que la plupart des réponses ici étaient soit trop complexes, soit ne fournissaient pas vraiment ce que je voulais.

J'ai écrit une feuille partielle très simple qui se trouve sur GitHub, disponible en tant que package Swift - HalfASheet

Il n'a probablement pas toutes les fonctionnalités des autres solutions, mais il fait ce qu'il doit faire. De plus, écrire le vôtre est toujours bon pour comprendre ce qui se passe.

Note - Deux choses - Tout d'abord, c'est vraiment en cours de développement, n'hésitez pas à l'améliorer, etc. Deuxièmement, je n'ai délibérément pas fait de .podspec car si vous développez pour SwiftUI, vous êtes au minimum sur iOS 13, et les Swift Packages sont tellement plus agréables à mon avis...

0voto

Yensi Vega Points 1

J'essayais de faire la même chose que demandé ici, afficher la feuille de partage de manière native en SwiftUI sans avoir à implémenter / importer un composant. J'ai trouvé cette solution sur https://jeevatamil.medium.com/how-to-create-share-sheet-uiactivityviewcontroller-in-swiftui-cef64b26f073

struct ShareSheetView: View {
    var body: some View {
        Button(action: actionSheet) {
            Image(systemName: "square.and.arrow.up")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 36, height: 36)
        }
    }

    func actionSheet() {
        guard let data = URL(string: "https://www.zoho.com") else { return }
        let av = UIActivityViewController(activityItems: [data], applicationActivities: nil)
        UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X