Advertisement
  1. Code
  2. iOS SDK

Wie man Ihre App für iOS 11 aktualisieren kann: Drag-and-drop

Scroll to top
Read Time: 13 min

() translation by (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

iOS 11 hat iOS, besonders für das iPad, dank Drag-and-drop zu einer echten Multitasking-Plattform gemacht. Dies verspricht, die Grenzen zwischen Apps zu verwischen und Inhalte können problemlos geteilt werden. Mit iOS 11 können Inhalte auf natürliche und intuitive Weise verschoben werden, wodurch die mobilen Geräte von Apple der Parität mit dem Reichtum der Desktop- und Laptop-Benutzer näher kommen.

Drag and Drop on the iPad between Photos and Mail source AppleDrag and Drop on the iPad between Photos and Mail source AppleDrag and Drop on the iPad between Photos and Mail source Apple

Mit dieser lang erwarteten Funktion können Sie Elemente an einen anderen Ort in derselben Anwendung oder in eine andere Anwendung ziehen. Dies funktioniert entweder über eine Split-Screen-Anordnung oder über das Dock mit einer kontinuierlichen Geste. Darüber hinaus können Benutzer nicht nur einzelne Elemente auswählen, sondern mehrere Elemente gleichzeitig ziehen. Viele Apps, einschließlich System-Apps wie Fotos und Dateien, nutzen die Mehrfachauswahl und das Ziehen mehrerer Dateien.

iOS 11s Files AppiOS 11s Files AppiOS 11s Files App

Die Ziele dieses Tutorials

In diesem Tutorial lernen Sie Drag-and-drop kennen und lernen anschließend die Architektur und Strategie der Verwendung des neuen Drag-and-drop SDK in einer App mit Tabellenansicht kennen. Ich möchte Entwicklern wie Ihnen helfen, Ihre Apps an das aufkommende Verhalten der Benutzeroberfläche anzupassen, das in zukünftigen iOS-Apps zum Standard wird.

In diesem Tutorial werden wir Folgendes behandeln:

  • Drag-and-drop Technik verstehen
  • Drag-and-drop in einer Tabellenansicht implementieren
  • Die besten Methoden des Drag-and-drops

Im zweiten Teil dieses Tutorials werden wir die praktischen Schritte durchgehen, mit denen eine einfache Tabellenansicht-App Drag-and-drop nutzen kann, beginnend mit einer der Standardvorlagen für Tabellenansichten von Apple, die beim Erstellen eines neuen Projekts in Xcode verfügbar sind 9. Klonen Sie das GitHub-Repo des Tutorials, wenn Sie mitmachen möchten.

Vorausgesetztes Wissen

In diesem Tutorial wird davon ausgegangen, dass Sie Erfahrung als iOS-Entwickler haben und UIKit-Bibliotheken in Swift oder Objective-C, einschließlich UITableView, verwendet haben und mit Delegaten und Protokollen vertraut sind.

Drag-and-drop Technik verstehen

Unter Verwendung der Apple-Nomenklatur wird ein visuelles Element vom Quellspeicherort gezogen und am Zielspeicherort abgelegt. Dies wird als Drag-Aktivität bezeichnet, wobei die Aktivität entweder in einer einzelnen App (iPad und iPhone unterstützt) oder in zwei Apps (nur auf dem iPad verfügbar) stattfindet.

Während einer Drag Session sind sowohl die Quell- als auch die Ziel-App weiterhin aktiv und werden wie gewohnt ausgeführt, wodurch Benutzerinteraktionen unterstützt werden. Im Gegensatz zu macOS unterstützt iOS mehrere gleichzeitige Drag-Aktivitäten mit mehreren Fingern.

Konzentrieren wir uns jedoch auf ein einzelnes Drag-Element und darauf, wie es ein Versprechen als Vertrag für seine Datendarstellung verwendet.

Drag-Elemente als Promises

Jedes Drag-Element kann als Promise betrachtet werden, als enthaltene Datendarstellung, die von einer Quelle an ihr Ziel gezogen und dort abgelegt wird. Das Drag-Element verwendet einen Elementanbieter, der seine registerTypeIdentifiers mit einheitlichen Typ-IDs auffüllt. Hierbei handelt es sich um einzelne Datendarstellungen, die zusammen mit einem Vorschaubild (das visuell unter dem Berührungspunkt des Benutzers angeheftet ist) an das beabsichtigte Ziel gesendet werden sollen unten:

A UIDragItem source AppleA UIDragItem source AppleA UIDragItem source Apple

Das Drag-Element wird über das UIDragInteractionDelegate vom Quellspeicherort erstellt und über das UIDropInteractionDelegate am Zielspeicherort verarbeitet. Der Quellspeicherort muss dem NSItemProviderWriting-Protokoll entsprechen, und der Zielspeicherort muss dem NSItemProviderReading-Protokoll entsprechen.

Dies ist eine grundlegende Übersicht über die Nominierung einer Ansicht als Drag-Element durch Promises. Lassen Sie uns sehen, wie wir eine Drag-Quelle aus einer Ansicht implementieren, bevor Sie das Drop-Ziel festlegen.

Implementieren einer Drag Source

Wenn wir unsere Aufmerksamkeit auf den ersten Teil des Drag-and-drop - die Drag-Quelle - richten, müssen wir die folgenden Schritte ausführen, wenn der Benutzer eine Drag-Aktivität initiiert:

  1. Passen Sie die Ansicht an das UIDragInterationDelegate-Protokoll an.
  2. Deklarieren Sie die Datenelemente, die das Elementversprechen bilden, über dragInteraction(_:itemsForBeginning:).
  3. Füllen Sie die Drag Session mit den Drag-Elementen, um den Benutzer darauf vorzubereiten, die Elemente an das Ablageziel zu ziehen.
Implementing a Drag Source source AppleImplementing a Drag Source source AppleImplementing a Drag Source source Apple

Als Erstes müssen Sie Ihre nominierte Ansicht wie folgt an das UIDragInterationDelegate-Protokoll anpassen, indem Sie eine neue UIDragInteraction-Instanz erstellen und sie der addInteraction-Eigenschaft Ihrer ViewController-Ansicht sowie ihrem Delegaten wie folgt zuordnen:

1
    let dragInteraction = UIDragInteraction(delegate: dragInteractionDelegate)
2
    view.addInteraction(dragInteraction)

Nachdem Sie Ihre Drag-Quelle deklariert haben, erstellen Sie ein Drag-Element, das im Wesentlichen ein Versprechen der Datendarstellung ist, indem Sie die Delegatmethode dragInteraction(_:itemsForBeginning:) implementieren, die das System aufruft, um ein Array von einem oder mehreren Drag-Elementen zum Auffüllen zurückzugeben die Elementeigenschaft der Drag Session. Im folgenden Beispiel wird ein NSItemProvider aus einem Bildversprechen erstellt, bevor ein Array von Datenelementen zurückgegeben wird:

1
func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
2
    guard let imagePromise = imageView.image else { 
3
		return [] //By returning an empty array you disable dragging. 
4
	}
5
  let provider = NSItemProvider(object: imagePromise)
6
  let item = UIDragItem(itemProvider: provider)     
7
	return [item]
8
}

Die obige Delegierungsmethode reagiert auf eine Ziehanforderung, die ausgelöst wird, wenn der Benutzer mit dem Ziehen des Elements beginnt, wobei der Gestenerkenner (UIGestureRecognizer) eine Nachricht "drag started" an das System zurücksendet. Dies ist es, was im Wesentlichen die "Drag-Session" initialisiert.

Als Nächstes fahren wir mit der Implementierung des Ablageziels fort, um das im Session initiierte Array von Drag-Elementen zu verarbeiten.

Implementieren eines Drop-Ziels

Um Ihre nominierte Ansicht so anzupassen, dass Daten als Teil des Ablageziels akzeptiert und konsumiert werden, müssen Sie die folgenden Schritte ausführen:

  1. Instanziieren Sie eine DropInteraction.
  2. Deklarieren Sie die Datenelementtypen (falls vorhanden), die Sie akzeptieren, mit dropInteraction(_:canHandle:).
  3. Implementieren Sie einen Drop-Vorschlag mit der Protokollmethode dropInteraction(_:sessionDidUpdate:) und geben Sie an, ob Sie die Sitzung kopieren, verschieben, ablehnen oder abbrechen möchten.
  4. Verwenden Sie zum Schluss die Datenelemente mit der Protokollmethode dropInteraction(_:performDrop:).
Implementing a Drop Destination source AppleImplementing a Drop Destination source AppleImplementing a Drop Destination source Apple

So wie wir unsere Ansicht so konfiguriert haben, dass das Ziehen aktiviert wird, konfigurieren wir unsere nominierte Ansicht symmetrisch so, dass sie abgelegte Elemente aus einer Drag Session akzeptiert. Dabei verwenden wir UIDropinteractionDelegate und implementieren die DropInteraction-Delegatmethode:

1
let dropInteraction = UIDropInteraction(delegate: dropInteractionDelegate)
2
    view.addInteraction(dropInteraction)

Um festzulegen, ob eine Ansicht Drag-Elemente akzeptieren kann oder ablehnt, implementieren wir die Protokollmethode dropInteraction(_:canHandle:). Mit der folgenden Methode kann unsere Ansicht dem System mitteilen, ob es die Elemente akzeptieren kann, indem der Typ der Objekte angegeben wird, die es empfangen kann - in diesem Fall UIImages.

1
func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
2
    // Explicitly state the acceptable drop item type here
3
    return session.canLoadObjects(ofClass: UIImage.self)
4
}

Wenn das Ansichtsobjekt keine Drop-Interaktionen akzeptiert, sollten Sie von dieser Methode false zurückgeben.

Binden Sie als Nächstes einen Drop-Vorschlag, um Daten aus der Drop-Session zu akzeptieren. Obwohl dies eine optionale Methode ist, wird dringend empfohlen, diese Methode zu implementieren, da sie visuelle Hinweise darauf liefert, ob das Ablegen zum Kopieren, Verschieben des Elements oder zum vollständigen Ablehnen des Ablegens führt. Durch Implementieren der Protokollmethode dropInteraction(_:sessionDidUpdate:), die ein UIDropProposal zurückgibt, geben Sie den Vorschlagstyp mithilfe des spezifischen Aufzählungstyps für Operationen (UIDropOperation) an. Die gültigen Typen, die Sie zurückgeben können, sind:

  • cancel
  • forbidden
  • copy
  • move
1
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
2
        // Signal to the system that you will move the item from the source app (you could also state .copy to copy as opposed to move)
3
        return UIDropProposal(operation: .move)
4
}

Um den Datenelementinhalt an Ihrem Zielspeicherort zu nutzen, implementieren Sie die Protokollmethode dropInteraction(_:performDrop:) in der Hintergrundwarteschlange (und nicht in der Hauptwarteschlange - dies stellt die Reaktionsfähigkeit sicher). Dies ist unten dargestellt:

1
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
2
    // Consume UIImage drag items
3
    session.loadObjects(ofClass: UIImage.self) { items in
4
        let images = items as! [UIImage]
5
        self.imageView.image = images.first
6
    }
7
}

Wir haben gezeigt, wie Sie Drag & Drop in einer benutzerdefinierten Ansicht implementieren. Gehen wir nun zum praktischen Teil dieses Lernprogramms über und implementieren Drag & Drop in einer App mit Tabellenansicht.

Drag-and-drop in einer Tabellenansicht implementieren

Bisher haben wir diskutiert, wie Drag-and-drop in benutzerdefinierten Ansichten implementiert werden kann. Apple hat es jedoch auch einfach gemacht, Tabellen- und Sammlungsansichten durch Drag-and-drop zu erweitern. Während Textfelder und Ansichten das Ziehen und Ablegen automatisch unterstützen, stellen Tabellen- und Sammlungsansichten bestimmte Methoden, Delegaten und Eigenschaften zum Anpassen ihres Drag-and-drop-Verhaltens bereit. Wir werden uns das in Kürze ansehen.

Erstellen Sie zunächst ein neues Projekt in Xcode 9 und stellen Sie sicher, dass Sie im Vorlagenfenster die Master-Detail-App auswählen:

Creating a new Project in XcodeCreating a new Project in XcodeCreating a new Project in Xcode

Bevor Sie mit den restlichen Schritten beginnen, erstellen Sie das Projekt, führen Sie es aus und spielen Sie ein wenig damit herum. Sie werden sehen, dass ein neues Zeitstempeldatum generiert wird, wenn Sie die Plus-Taste (+) auswählen. Wir werden diese App verbessern, indem wir dem Benutzer erlauben, die Zeitstempel zu ziehen und zu ordnen.

Drag-and-drop wird in Tabellenansichten (sowie Sammlungen) über spezielle APIs unterstützt, die das Ziehen und Ablegen mit Zeilen ermöglichen, indem unsere Tabellenansicht so angepasst wird, dass sowohl die Protokolle UITableViewDragDelegate als auch UITableViewDropDelegate übernommen werden. Öffnen Sie die Datei MasterViewController.swift und fügen Sie der Methode viewDidLoad() Folgendes hinzu:

1
override func viewDidLoad() {
2
  super.viewDidLoad()
3
    ...
4
	self.tableView.dragDelegate = self
5
	self.tableView.dropDelegate = self
6
	...

Wie bei benutzerdefinierten Ansichten müssen wir die neue Drag Session behandeln, wenn der Benutzer eine ausgewählte Zeile oder mehrere Zeilen/Auswahlen zieht. Wir tun dies mit der Delegatenmethode tableView(_:itemsForBeginning:at:). Bei dieser Methode geben Sie entweder ein ausgefülltes Array zurück, das mit dem Ziehen der ausgewählten Zeilen beginnt, oder ein leeres Array, um zu verhindern, dass der Benutzer Inhalte aus diesem bestimmten Indexpfad zieht.

Fügen Sie Ihrer MasterViewController.swift-Datei die folgende Methode hinzu:

1
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
2
        
3
        let dateItem = self.objects[indexPath.row] as! String
4
        
5
        let data = dateItem.data(using: .utf8)
6
        let itemProvider = NSItemProvider()
7
        
8
        itemProvider.registerDataRepresentation(forTypeIdentifier: kUTTypePlainText as String, visibility: .all) { completion in
9
            completion(data, nil)
10
            return nil
11
        }
12
        
13
        return [
14
            UIDragItem(itemProvider: itemProvider)
15
        ]
16
  }

Ein Teil des hinzugefügten Codes sollte Ihnen bereits aus dem vorherigen Abschnitt bekannt sein. Im Wesentlichen erstellen wir jedoch ein Datenelement aus dem ausgewählten Objekt, verpacken es in einen NSItemProvider und geben es in ein DragItem zurück.

Wenden Sie sich dem Aktivieren der Drop-Session zu und fügen Sie die folgenden zwei Methoden hinzu:

1
func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool {
2
        return session.canLoadObjects(ofClass: NSString.self)
3
    }
4
    
5
    func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
6
        
7
        if tableView.hasActiveDrag {
8
            if session.items.count > 1 {
9
                return UITableViewDropProposal(operation: .cancel)
10
            } else {
11
                return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
12
            }
13
        } else {
14
            return UITableViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
15
        }
16
    }

Die erste Methode teilt dem System mit, dass es String-Datentypen als Teil seiner Drop-Session verarbeiten kann. Die zweite Delegatmethode, tableView(_:dropSessionDidUpdate:withDestinationIndexPath:), verfolgt den potenziellen Speicherort und benachrichtigt die Methode bei jeder Änderung. Außerdem wird visuelles Feedback angezeigt, um den Benutzer mithilfe eines kleinen visuellen Symbols darüber zu informieren, ob ein bestimmter Ort verboten oder akzeptabel ist.

Zuletzt behandeln wir das Löschen und verbrauchen das Datenelement, rufen tableView(_:performDropWith:) auf, rufen die gezogene Datenelementzeile ab, aktualisieren die Datenquelle unserer Tabellenansicht und fügen die erforderlichen Zeilen in die Tabelle ein.

1
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
2
        let destinationIndexPath: IndexPath
3
        
4
        if let indexPath = coordinator.destinationIndexPath {
5
            destinationIndexPath = indexPath
6
        } else {
7
            // Get last index path of table view.
8
            let section = tableView.numberOfSections - 1
9
            let row = tableView.numberOfRows(inSection: section)
10
            destinationIndexPath = IndexPath(row: row, section: section)
11
        }
12
        
13
        coordinator.session.loadObjects(ofClass: NSString.self) { items in
14
            // Consume drag items.
15
            let stringItems = items as! [String]
16
            
17
            var indexPaths = [IndexPath]()
18
            for (index, item) in stringItems.enumerated() {
19
                let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
20
                self.objects.insert(item, at: indexPath.row)
21
                indexPaths.append(indexPath)
22
            }
23
            
24
            tableView.insertRows(at: indexPaths, with: .automatic)
25
        }
26
    }

Weiterführende Literatur

Weitere Informationen zur Unterstützung von Drag-and-drop in Ihren Tabellenansichten finden Sie in der Apple-eigenen Entwicklerdokumentation zur Unterstützung von Drag-und-drop in Tabellenansichten.

Die besten Methoden des Drag-and-drops

Der von uns behandelte Inhalt soll Ihnen bei der Implementierung von Drag-and-drop in Ihren Apps helfen, sodass Benutzer sich visuell und interaktiv in Inhalten innerhalb ihrer vorhandenen Apps sowie zwischen Apps bewegen können.

Neben dem technischen Wissen über die Implementierung von Drag-and-drop ist es jedoch unbedingt erforderlich, dass Sie sich die Zeit nehmen, um zu überlegen, wie Sie Drag-and-drop implementieren würden. Befolgen Sie dabei die von Apple in den Human Interface Guidelines (HIG) empfohlenen Best Practices in um Benutzern die bestmögliche Benutzererfahrung für iOS 11 zu bieten.

Zum Abschluss werden wir einige der wichtigsten Aspekte ansprechen, die zu berücksichtigen sind, beginnend mit visuellen Hinweisen. Laut HIG besteht die grundlegende Erfahrung mit Drag-and-drop darin, dass visuelle Hinweise dem Benutzer bei der Interaktion mit bestimmten Inhalten eine aktive Drag-Session anzeigen, die durch das Aufsteigen des Inhaltselements gekennzeichnet ist, sowie ein Abzeichen, das angibt, wann das Ablegen erfolgt oder ist nicht möglich.

Photos on iOS 11 source ApplePhotos on iOS 11 source ApplePhotos on iOS 11 source Apple

Wir haben diese bewährte Methode bereits in unseren früheren Beispielen verwendet, als wir die tableView(_:dropSessionDidUpdate:withDestinationIndexPath:)-Methode eingefügt haben, mit der angegeben wird, ob das Ablageziel ein Verschieben, Kopieren oder Verboten ist. Sie sollten mit benutzerdefinierten Ansichten und Interaktionen sicherstellen, dass Sie die erwarteten Verhaltensweisen beibehalten, die andere iOS 11-Apps, insbesondere System-Apps, unterstützen.

Ein weiterer wichtiger Aspekt ist die Entscheidung, ob Ihre Drag-Session zu einem Verschieben oder Kopieren führt. Als allgemeine Faustregel schlägt Apple vor, dass das Arbeiten in derselben App im Allgemeinen zu einer Verschiebung führen sollte, während es sinnvoller ist, das Datenelement zu kopieren, wenn Sie zwischen verschiedenen Apps ziehen. Obwohl es Ausnahmen gibt, besteht das zugrunde liegende Prinzip natürlich darin, dass es für den Benutzer sinnvoll sein sollte und dass das, was er erwartet, geschehen sollte.

Sie sollten auch über Quellen und Ziele nachdenken und darüber, ob es sinnvoll ist, etwas zu ziehen oder nicht.

Werfen wir einen Blick auf einige Apple-eigene Systemdienstprogramme. Mit Notizen können Sie beispielsweise Textinhalte über einen geteilten Bildschirm auswählen und an andere Stellen in der App oder auf andere Apps auf dem iPad übertragen. Mit der Erinnerungs-App können Sie Erinnerungselemente von einer Liste in eine andere Liste verschieben. Denken Sie an die Funktionalität, wenn Sie entscheiden, wie Benutzer Ihre Inhalte verwenden.

Apple geht davon aus, dass alle bearbeitbaren Inhalte das Akzeptieren von abgelegten Inhalten unterstützen sollten und dass alle auswählbaren Inhalte ziehbare Inhalte akzeptieren sollten, zusätzlich zum Kopieren und Einfügen für diese Elementtypen. Durch die Nutzung von Standard-Systemtextansichten und Textfeldern erhalten Sie Unterstützung für Drag-and-drop aus der Box.

Sie sollten auch das Ziehen und Ablegen mehrerer Elemente unterstützen, anstatt nur einzelne Elemente zu unterstützen, wobei Benutzer mehr als einen Finger verwenden können, um mehrere Elemente gleichzeitig auszuwählen und die ausgewählten Elemente in einer Gruppe zu stapeln, die an den vorgesehenen Zielen abgelegt werden soll. Ein Beispiel hierfür ist die Auswahl mehrerer Bilder in der Foto-App oder mehrerer Dateien in der Datei-App.

Eine letzte Richtlinie besteht darin, den Benutzern die Möglichkeit zu geben, eine Aktion umzukehren oder einen Abwurf rückgängig zu machen. Benutzer sind seit langem an das Konzept gewöhnt, eine Aktion in den meisten gängigen Apps rückgängig zu machen, und Drag-and-drop sollte keine Ausnahme sein. Benutzer sollten das Vertrauen haben, ein Ziehen und Ablegen zu initiieren und diese Aktion rückgängig zu machen, wenn sie das Element am falschen Ziel ablegen.

Weiterführende Literatur

Es gibt noch viel mehr die besten Methoden für Drag-and-drop, die über das hinausgehen, was wir uns angesehen haben, einschließlich der Unterstützung von Hinweisen auf abgelegte visuelle Indikatoren, der Anzeige fehlgeschlagener Aktionen für abgelegte Aktionen und Fortschrittsanzeigen für nicht sofortige Drag-Session, z.B. Datenübertragungen. Die vollständige Liste der Best Practices finden Sie in den Richtlinien für die iOS-Benutzeroberfläche von Apple zum Ziehen und Ablegen.

Schlussfolgerung

In diesem Tutorial haben Sie gelernt, wie Sie Ihre iOS-Apps mithilfe von iOS 11 mit Drag-and-drop anreichern können. Dabei haben wir auch gelernt, wie Sie benutzerdefinierte Ansichten und Tabellenansichten als Drag-Quellen und Drop-Ziele aktivieren können.

Als Teil der iOS-Entwicklung hin zu einer gestengesteuerteren Benutzeroberfläche wird Drag-and-drop zweifellos schnell zu einer erwarteten Funktion für Benutzer im gesamten System. Daher sollten auch alle Apps von Drittanbietern konform sein. Und genauso wichtig wie das Implementieren von Drag-and-drop, müssen Sie es richtig implementieren, damit es für Benutzer zur zweiten Natur wird und Einfachheit und Funktionalität umfasst.

Und während Sie hier sind, lesen Sie einige unserer anderen Beiträge zur Entwicklung von iOS-Apps!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.