How to dismiss a modal in iOS?

Luk Modaler Intuitivt på iOS

09/08/2023

Rating: 4.07 (5134 votes)
Indholdsfortegnelse

Hvordan Lukker Man en Modal på iOS? En Dybdegående Guide

At håndtere modale vinduer på iOS, især når det kommer til at lukke dem, kan være en kilde til forvirring for mange udviklere. Traditionelt set kræver det et tryk på en "luk"-knap eller en gestus som at trække ned. Denne artikel udforsker forskellige metoder til at implementere en intuitiv og brugercentreret lukningsmekanisme for modaler på iOS, med fokus på interaktiv træk-ned-funktionalitet og håndtering af baggrunds-scrolling.

How do I Close a modal?
Tip: You can also use the following javascript to close the modal by clicking outside of the modal content (and not just by using the "x" or "cancel" button to close it): Well organized and easy to understand Web building tutorials with lots of examples of how to use HTML, CSS, JavaScript, SQL, Python, PHP, Bootstrap, Java, XML and more.

Interaktiv Lukning af Modaler med Træk-Ned Gestus

En af de mest moderne og intuitive måder at lukke en modal på iOS er ved at tillade brugeren at trække den nedad. Denne tilgang efterligner den naturlige adfærd, man ser i mange native iOS-apps, og giver en følelse af direkte manipulation. Nedenfor beskrives den tekniske implementering af denne funktion ved brug af Swift og UIKit.

Grundlæggende Arkitektur

For at opnå denne funktionalitet, benytter vi os af et samarbejde mellem tre nøglekomponenter:

  • View Controller: Ansvarlig for at præsentere modalen og håndtere overgangen.
  • Dismiss Animator: Definerer den visuelle animation, når modalen lukkes.
  • Interactor: Styrer den interaktive del af lukningen, dvs. brugerens træk-bevægelse.

Implementering i Swift

Lad os dykke ned i koden:

View Controller Konfiguration

I din præsentations-View Controller skal du initialisere en `Interactor` og tildele den til modallens `interactor`-egenskab, samt sætte `transitioningDelegate`.

import UIKit class ViewController: UIViewController { let interactor = Interactor() override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if let destinationViewController = segue.destinationViewController as? ModalViewController { destinationViewController.transitioningDelegate = self destinationViewController.interactor = interactor } } } extension ViewController: UIViewControllerTransitioningDelegate { func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return DismissAnimator() } func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { return interactor.hasStarted ? interactor: nil } } 
Dismiss Animator

Denne klasse implementerer `UIViewControllerAnimatedTransitioning` og styrer selve animationen. Når brugeren trækker ned, flyttes modalens view ud af skærmen.

import UIKit class DismissAnimator: NSObject { let transitionDuration = 0.6 } extension DismissAnimator: UIViewControllerAnimatedTransitioning { func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { return transitionDuration } func animateTransition(transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey), let containerView = transitionContext.containerView() else { return } if transitionContext.transitionWasCancelled() { // Hvis animationen afbrydes, sæt den tilbage containerView.insertSubview(fromVC.view, atIndex: 0) } else { let screenBounds = UIScreen.mainScreen().bounds let bottomLeftCorner = CGPoint(x: 0, y: screenBounds.height) let finalFrame = CGRect(origin: bottomLeftCorner, size: screenBounds.size) UIView.animateWithDuration(transitionDuration(transitionContext), animations: { fromVC.view.frame = finalFrame }, completion: { transitionContext.completeTransition(!$0) }) } } } 
Interactor

En subklasse af `UIPercentDrivenInteractiveTransition`, der fungerer som en state machine for brugerens interaktion. Den holder styr på, om brugeren har startet en gestus, og om den skal fuldføres.

import UIKit class Interactor: UIPercentDrivenInteractiveTransition { var hasStarted = false var shouldFinish = false } 
Modal View Controller

I den præsenterede modal-View Controller skal du tilføje en `UIPanGestureRecognizer` og forbinde dens handlinger med interactor.

How to prevent background scrolling on iOS while a modal is open?
There's no need to manually remove the fixed positioning on the body, because this is set through the .modal-open class, which Bootstrap removes when the modal is closed. Demo Put it all together, and now you can prevent background scrolling on iOS while a modal is open without losing your scroll position!
import UIKit class ModalViewController: UIViewController { var interactor: Interactor! // Tilknyttes fra præsentations-VC override func viewDidLoad() { super.viewDidLoad() let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:))) view.addGestureRecognizer(panGesture) } @objc func handlePanGesture(_ sender: UIPanGestureRecognizer) { guard let interactor = interactor else { return } let translation = sender.translationInView(view) let velocity = sender.velocityInView(view) // Bestem, om gestussen skal starte interaktionen if sender.state == .Began { interactor.hasStarted = true dismiss(animated: true, completion: nil) } else if sender.state == .Changed { // Beregn fremdrift og opdater animationen let percent = abs(translation.y) / view.bounds.height interactor.shouldFinish = percent > 0.3 // Tærskel for fuldførelse interactor.update(percent) } else if sender.state == .Ended || sender.state == .Cancelled { // Fuldfør eller afbryd animationen baseret på tærsklen if interactor.shouldFinish { interactor.finish() } else { interactor.cancel() } interactor.hasStarted = false } } } 

Forhindring af Baggrunds-Scrolling på iOS

Når en modal præsenteres, er det ofte ønskeligt at forhindre brugeren i at scrolle i baggrundens indhold. Dette skaber en klarere brugeroplevelse, hvor fokus udelukkende er på modallen. En almindelig metode til dette, især i webudvikling med Bootstrap, involverer at ændre `body`-elementets stil. Selvom den givne løsning er for web, kan princippet overføres til native iOS-udvikling ved at deaktivere scrolling på den underliggende View Controller's scroll view, mens modallen er synlig.

Metode til Web-baserede Modaler (Bootstrap)

For webudviklere, der bruger Bootstrap, kan følgende CSS og JavaScript forhindre baggrunds-scrolling:

  1. CSS: Når en modal åbnes, tilføjes klassen `.modal-open` til `body`. Tilføj følgende styles til denne klasse for at fryse baggrunden:
    body.modal-open { bottom: 0; left: 0; position: fixed; right: 0; top: 0; } 
  2. JavaScript: For at undgå et spring til toppen af siden, når modallen åbnes, gemmes den aktuelle scroll-position og anvendes som en negativ `top`-værdi på `body`. Når modallen lukkes, nulstilles dette.
    $(function() { var $window = $(window); var $body = $("body"); var $modal = $(".modal"); var scrollDistance = 0; $modal.on("show.bs.modal", function() { scrollDistance = $window.scrollTop(); $body.css("top", scrollDistance * -1); }); $modal.on("hidden.bs.modal", function() { $body.css("top", ""); $window.scrollTop(scrollDistance); }); }); 

Native iOS Tilgang til Scroll-kontrol

I en native iOS-app, hvis din hoved-View Controller indeholder et `UIScrollView` (eller en `UITableView`/`UICollectionView`), kan du midlertidigt deaktivere scrolling, mens modallen er aktiv. Dette kan gøres ved at sætte `scrollView.isScrollEnabled = false` i den præsenterende View Controller, når modallen vises, og sætte det tilbage til `true`, når modallen lukkes.

CSS-baseret Lukning af Modaler

For simple modaler, der ikke kræver avanceret interaktivitet, kan CSS også bruges til at håndtere lukning. Dette er især relevant for web-baserede komponenter, hvor en "X"-knap eller en "Annuller"-knap kan styre modalens synlighed.

Eksempel på CSS og HTML Struktur

Her er et grundlæggende eksempel på, hvordan en modal kan struktureres og styres med CSS:

HTML:

×
Remember me
Forgot password?

CSS:

/* Generel styling for alle elementer */ * {box-sizing: border-box} /* Styling for body og modals */ body { font-family: Arial, Helvetica, sans-serif; } /* The Modal (background) */ .modal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ left: 0; top: 0; width: 100%; /* Full width */ height: 100%; /* Full height */ overflow: auto; /* Enable scroll if needed */ background-color: rgb(0,0,0); /* Fallback color */ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ padding-top: 60px; } /* Modal Content/Box */ .modal-content { background-color: #fefefe; margin: 5% auto 15% auto; /* 5% from the top, 15% from the bottom and centered */ border: 1px solid #888; width: 80%; /* Could be more or less, depending on screen size */ } /* The Modal Close Button (x) */ .close { position: absolute; top: 0; right: 25px; color: #000; font-size: 35px; font-weight: bold; } .close:hover, .close:focus { color: red; cursor: pointer; } /* Add Zoom Animation */ .animate { -webkit-animation-name: zoom; -webkit-animation-duration: 0.4s; animation-name: zoom; animation-duration: 0.4s } @-webkit-keyframes zoom { from {-webkit-transform: scale(0.1)} to {-webkit-transform: scale(1.0)} } @keyframes zoom { from {transform: scale(0.1)} to {transform: scale(1.0)} } /* Container styling */ .container { padding: 16px; } /* Style Cancel and Delete Buttons */ .cancelbtn, .deletebtn { width: auto; padding: 10px 18px; background-color: #f44336; } .cancelbtn { background-color: #f1f1f1; color: black; } /* Float cancel and delete buttons and add an equal width */ .cancelbtn, .deletebtn { float: left; width: 50%; } /* Clear floats */ .clearfix::after { content: ""; clear: both; display: table; } /* Change styles for cancel button and delete button on extra small screens */ @media screen and (max-width: 300px) { .cancelbtn, .deletebtn { width: 100%; } } 

Opsummering og Bedste Praksis

Lukning af modaler på iOS kan gøres på flere måder, fra den enkle CSS-styrede tilgang til den avancerede interaktive træk-ned-gestus. Valget af metode afhænger af den ønskede brugeroplevelse og kompleksiteten af applikationen.

Nøglepunkter at huske:**

  • Intuitivitet: Stræb efter at efterligne velkendte brugerinteraktioner, som træk-ned-lukning.
  • Feedback: Giv visuel feedback til brugeren under interaktionen, f.eks. ved at vise, hvor langt de har trukket modallen.
  • Scroll-kontrol: Forhindr baggrunds-scrolling, når det er relevant, for at fastholde brugerens fokus.
  • Tilgængelighed: Sørg for, at der altid er en alternativ metode til at lukke modallen, f.eks. en tydelig luk-knap.
  • Testning: Test grundigt på forskellige iOS-versioner og enheder for at sikre en ensartet oplevelse.

Ved at anvende disse principper kan du skabe modale vinduer, der ikke kun er funktionelle, men også bidrager positivt til den samlede brugeroplevelse på iOS-enheder.

How to dismiss a modal in iOS?
To dismiss a modal in iOS, you can swipe down. For example, this functionality can be found in apps like Twitter and Snapchat. However, the implementation details may vary depending on the specific modal library or framework being used.

Ofte Stillede Spørgsmål (FAQ)

Q: Hvordan lukker jeg en modal med en knap i Swift?
A: Du kan kalde `dismissViewControllerAnimated(true, completion: nil)` fra den præsenterede modal-View Controller, når der trykkes på en knap.

Q: Kan jeg tilpasse animationen, når en modal lukkes?
A: Ja, ved at implementere `UIViewControllerTransitioningDelegate` og levere en brugerdefineret `DismissAnimator`, der overholder `UIViewControllerAnimatedTransitioning`-protokollen.

Q: Hvad er den bedste måde at forhindre baggrunds-scrolling på iOS?
A: Den mest almindelige metode er at deaktivere scrolling på den underliggende `UIScrollView` (eller dens subklasser) mens modallen er synlig.

Q: Hvordan håndterer jeg afbrydelser af træk-ned-gestussen?
A: Brug `interactor.cancel()` metoden, når brugerens gestus ikke opfylder tærsklen for at lukke modallen.

Hvis du vil læse andre artikler, der ligner Luk Modaler Intuitivt på iOS, kan du besøge kategorien Mobil.

Go up