Come aggiornare la tua app per iOS 11 trascina e rilascia

Cosa starai creando

iOS 11 ha elevato iOS, in particolare per l'iPad, in una vera piattaforma multi-tasking, grazie a Drag and Drop. Ciò promette di sfumare i confini tra le app, consentendo di condividere facilmente i contenuti. Sfruttando il multi-touch, iOS 11 consente di spostare i contenuti in modo naturale e intuitivo, avvicinando i dispositivi mobili di Apple alla parità con la ricchezza di cui godono gli utenti desktop e laptop.


Questa funzionalità tanto attesa consente di trascinare elementi in un'altra posizione nella stessa applicazione o in un'altra applicazione. Funziona tramite una disposizione a schermo diviso o tramite il dock, usando un gesto continuo. Inoltre, gli utenti non sono limitati alla sola selezione di singoli articoli, ma possono trascinare più oggetti contemporaneamente. Molte app, incluse app di sistema come Foto e File, sfruttano la selezione multipla e il trascinamento di più file.

Obiettivi di questo tutorial

Questo tutorial ti introdurrà al trascinamento della selezione, per poi approfondire l'architettura e la strategia dell'utilizzo del nuovo SDK Drag and Drop in un'applicazione basata su visualizzazione tabella. Voglio aiutare gli sviluppatori come te a conformare le tue app al comportamento dell'interfaccia utente emergente che diventerà standard nelle future app iOS. 

In questo tutorial, tratteremo quanto segue:

  • Capire Drag and Drop
  • Implementazione del trascinamento in una vista tabella 
  • Trascina e lascia le migliori pratiche

Nella seconda parte di questo tutorial, verranno illustrati i passaggi pratici per abilitare una semplice applicazione di visualizzazione tabella per sfruttare il trascinamento della selezione, a partire da uno dei modelli di visualizzazione tabella predefiniti di Apple disponibili quando si crea un nuovo progetto in Xcode 9. Andare avanti e clonare il repository GitHub del tutorial se si vuole seguire.

Conoscenza presunta

Questo tutorial presume che tu abbia esperienza come sviluppatore iOS e che abbia utilizzato le librerie UIKit in Swift o Objective-C, incluso UITableView, e che hai una certa dimestichezza con i delegati e i protocolli.

Capire Drag and Drop

Usando la nomenclatura di Apple, un elemento visivo viene trascinato dalla posizione di origine e lasciato cadere nella posizione di destinazione. Si parla di attività di trascinamento, con attività che si svolgono all'interno di una singola app (supportate da iPad e iPhone) o su due app (disponibili solo su iPad). 

Mentre è in corso una sessione di trascinamento, entrambe le app di origine e di destinazione sono ancora attive e vengono eseguite normalmente, supportando le interazioni dell'utente. Infatti, a differenza di macOS, iOS supporta più attività di trascinamento simultanee utilizzando più dita. 

Ma concentriamoci su un singolo elemento di trascinamento e su come utilizza una promessa come contratto per le sue rappresentazioni di dati. 

Trascina gli oggetti come promesse

Ogni elemento di trascinamento può essere pensato come una promessa, una rappresentazione di dati contenuti che verrà trascinata e rilasciata da un'origine alla sua destinazione. L'elemento di trascinamento utilizza un fornitore di elementi, che lo popola registeredTypeIdentifiers con identificatori di tipo uniforme, che sono rappresentazioni di dati individuali che si impegnerà a consegnare alla destinazione prevista insieme a un'immagine di anteprima (che è appuntata visivamente sul touchpoint dell'utente), come illustrato di seguito:


L'oggetto di trascinamento è costruito attraverso il UIDragInteractionDelegate dal luogo di origine e gestito nella posizione di destinazione tramite il UIDropInteractionDelegate. La posizione di origine deve essere conforme a NSItemProviderWriting protocollo e la posizione di destinazione deve essere conforme a NSItemProviderReading protocollo. 

Questa è una panoramica di base sulla nomina di una vista come oggetto trascinatore, attraverso le promesse. Vediamo come implementiamo una sorgente di trascinamento da una vista, prima di stabilire la destinazione di rilascio.

Implementazione di una sorgente di trascinamento

Concentrando la nostra attenzione sulla prima parte del drag & drop, la sorgente di trascinamento, è necessario eseguire i seguenti passaggi quando l'utente inizia un'attività di trascinamento:

  1. Conformare la vista al UIDragInterationDelegate protocollo.
  2. Dichiara gli articoli di dati che formeranno l'oggetto promesso, via dragInteraction (_: itemsForBeginning :)
  3. Compilare la sessione di trascinamento con gli elementi di trascinamento in preparazione per consentire all'utente di trascinare gli elementi nella destinazione di trascinamento.

La prima cosa che devi fare è conformare la tua vista nominata al UIDragInterationDelegate protocollo, creando un nuovo UIDragInteraction istanza e associandola al tuo ViewControllervista di s addInteraction proprietà e suo delegato, come segue: 

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

Dopo aver dichiarato la sorgente di trascinamento, si procede alla creazione di un elemento di trascinamento, essenzialmente una promessa della rappresentazione dei dati, implementando il metodo delegato dragInteraction (_: itemsForBeginning :), che il sistema chiama per restituire una matrice di uno o più elementi di trascinamento per popolare la proprietà degli elementi della sessione di trascinamento. L'esempio seguente crea un NSItemProvider da una promessa di immagine, prima di restituire una matrice di elementi di dati:

func dragInteraction (_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] guard let imagePromise = imageView.image else return [] // Restituendo un array vuoto si disabilita il trascinamento.  let provider = NSItemProvider (object: imagePromise) let item = UIDragItem (itemProvider: provider) return [item]

Il metodo delegate sopra risponde a una richiesta di trascinamento innescata quando l'utente inizia a trascinare l'oggetto, con il Gesture Recognizer (UIGestureRecognizer) invio di un messaggio "trascina avviata" al sistema. Questo è ciò che essenzialmente inizializza la "sessione di trascinamento". 

Successivamente, procediamo con l'implementazione della destinazione di rilascio, per gestire l'array di elementi di trascinamento avviati nella sessione.

Implementazione di una destinazione di rilascio

Allo stesso modo, per conformare la vista designata per accettare e utilizzare i dati come parte della destinazione di rilascio, è necessario completare i seguenti passaggi:

  1. Istanziare a DropInteraction.
  2. Dichiara i tipi di elementi dati (se presenti) che accetti, utilizzando dropInteraction (_: canHandle :).
  3. Implementare una proposta di drop usando il dropInteraction (_: sessionDidUpdate :) metodo di protocollo, che indica se si sta copiando, spostando, rifiutando o annullando la sessione.
  4. Infine, consumare gli elementi di dati utilizzando il dropInteraction (_: performDrop :) metodo di protocollo.

Proprio come abbiamo configurato la nostra vista per abilitare il drag, configureremo simmetricamente la nostra vista nominata per accettare gli elementi rilasciati da una sessione di trascinamento, usando il UIDropinteractionDelegate e implementando il suo DropInteraction metodo delegato:

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

Per designare se una vista è in grado di accettare elementi di trascinamento o si rifiuta, implementiamo il dropInteraction (_: canHandle :) metodo di protocollo. Il seguente metodo consente alla nostra vista di indicare al sistema se può accettare gli oggetti, dichiarando il tipo di oggetti che può ricevere, in questo caso UIImages.

func dropInteraction (_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool // Indicare esplicitamente il tipo di elemento drop accettabile qui return session.canLoadObjects (ofClass: UIImage.self)

Se l'oggetto vista non accetta alcuna interazione di rilascio, è necessario restituire false da questo metodo. 

Quindi, associare una proposta di rilascio per accettare i dati dalla sessione di rilascio. Sebbene si tratti di un metodo facoltativo, si consiglia vivamente di implementare questo metodo, poiché fornisce indicazioni visive sul fatto che il rilascio comporterà la copia dell'oggetto, lo spostamento o se il rilascio verrà rifiutato del tutto. Implementando il dropInteraction (_: sessionDidUpdate :) metodo di protocollo, che restituisce a UIDropProposal, si indica il tipo di proposta utilizzando il tipo di enumerazione dell'operazione specifica (UIDropOperation). I tipi validi che potresti restituire sono:

  • Annulla
  • proibito
  • copia
  • mossa
func dropInteraction (_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal // Segnala al sistema che sposterai l'elemento dall'app di origine (potresti anche specificare .copy da copiare anziché spostare) return UIDropProposal ( operazione: .move)

E infine, per consumare il contenuto dell'elemento di dati nella posizione di destinazione, si implementa il dropInteraction (_: performDrop :) metodo di protocollo nella coda di background (piuttosto che nella coda principale, questo garantisce reattività). Questo è illustrato di seguito: 

func dropInteraction (_ interaction: UIDropInteraction, performDrop session: UIDropSession) // Consuma UIImage drag items session.loadObjects (ofClass: UIImage.self) items in let images = items as! [UIImage] self.imageView.image = images.first

Abbiamo dimostrato come implementare il drag and drop in una visualizzazione personalizzata, quindi passiamo alla parte pratica di questo tutorial e implementiamo il drag and drop su un'app con una vista tabella.

Implementazione del trascinamento in una vista tabella

Finora, abbiamo discusso su come implementare il drag and drop nelle visualizzazioni personalizzate, ma Apple ha anche reso facile aumentare le visualizzazioni delle tabelle e le viste di raccolta con il drag and drop. Mentre i campi di testo e le viste supportano automaticamente il trascinamento della selezione, le viste delle tabelle e delle raccolte espongono metodi, delegati e proprietà specifici per la personalizzazione dei loro comportamenti di trascinamento e rilascio. Daremo un'occhiata a questo a breve.

Inizia creando un nuovo progetto in Xcode 9, assicurandoti di selezionare App per dettagli principali dalla finestra del modello:

Prima di iniziare a lavorare sugli altri passaggi, vai avanti e costruisci ed esegui il progetto e giocaci un po '. Vedrai che genera una nuova data di timestamp quando selezioni il plus (+). Miglioreremo questa app consentendo all'utente di trascinare e ordinare i timestamp. 

Il trascinamento della selezione è supportato nelle viste di tabelle (oltre che nelle raccolte) tramite API specializzate che consentono il trascinamento e il rilascio di righe, conformando la nostra vista tabella per adottare sia la UITableViewDragDelegate e UITableViewDropDelegate protocolli. Apri il MasterViewController.swift file e aggiungere il seguente al viewDidLoad () metodo:

override func viewDidLoad () super.viewDidLoad () ... self.tableView.dragDelegate = self self.tableView.dropDelegate = self ... 

Come abbiamo fatto con le visualizzazioni personalizzate, dobbiamo gestire la nuova sessione di trascinamento quando l'utente trascina una riga selezionata o più righe / selezioni. Lo facciamo con il metodo delegato tableView (_: itemsForBeginning: a :). All'interno di questo metodo, si restituisce un array popolato che avvia il trascinamento delle righe selezionate o un array vuoto per impedire all'utente di trascinare il contenuto da quel percorso dell'indice specifico. 

Aggiungi il seguente metodo al tuo MasterViewController.swift file:

func tableView (_ tableView: UITableView, itemsForBeginning session: UIDragSession, in indexPath: IndexPath) -> [UIDragItem] let DateItem = self.objects [indexPath.row] as! String let data = dataItem.data (usando: .utf8) let itemProvider = NSItemProvider () itemProvider.registerDataRepresentation (forTypeIdentifier: kUTTypePlainText as String, visibility: .all) completamento in completamento (data, nil) return nil return [UIDragItem ( itemProvider: itemProvider)]

Alcuni dei codici aggiunti dovrebbero già essere familiari dalla sezione precedente, ma in sostanza quello che stiamo facendo è creare un elemento dati dall'oggetto selezionato, avvolgerlo in un NSItemProvider, e restituirlo in a DragItem

Attirando la nostra attenzione per abilitare la sessione di rilascio, procedi con l'aggiunta dei seguenti due metodi:

func tableView (_ tableView: UITableView, canHandle session: UIDropSession) -> Bool return session.canLoadObjects (ofClass: NSString.self) func tableView (_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal if tableView.hasActiveDrag if session.items.count> 1 return UITableViewDropProposal (operation: .cancel) else return UITableViewDropProposal (operation: .move, intent: .insertAtDestinationIndexPath) else return UITableViewDropProposal (operazione:. copia, intento: .insertAtDestinationIndexPath)

Il primo metodo dice al sistema che può gestire i tipi di dati String come parte della sua sessione di rilascio. Il secondo metodo delegato, tableView (_: dropSessionDidUpdate: withDestinationIndexPath :), tiene traccia della potenziale posizione di rilascio, notificando il metodo ad ogni modifica. Visualizza anche un feedback visivo per far sapere all'utente se una posizione specifica è proibita o accettabile, utilizzando una piccola icona visiva. 

Infine, gestiamo il drop e consumiamo l'elemento dati, chiamando tableView (_: performDropWith :), recupero della riga di dati trascinati, aggiornamento dell'origine dati della vista tabella e inserimento delle righe necessarie nella tabella.

func tableView (_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) let destinationIndexPath: IndexPath if let indexPath = coordinator.destinationIndexPath destinationIndexPath = indexPath else // Ottieni l'ultimo percorso dell'indice della vista tabella. let section = tableView.numberOfSections - 1 let row = tableView.numberOfRows (inSection: section) destinationIndexPath = IndexPath (row: row, section: section) coordinator.session.loadObjects (ofClass: NSString.self) items in // Consume trascinare gli oggetti. let stringItems = items as! [String] var indexPaths = [IndexPath] () for (index, item) in stringItems.enumerated () let indexPath = IndexPath (row: destinationIndexPath.row + index, section: destinationIndexPath.section) self.objects.insert (item , a: indexPath.row) indexPaths.append (indexPath) tableView.insertRows (a: indexPaths, con: .automatic)

Ulteriori letture

Per ulteriori informazioni sul supporto del trascinamento e rilascio nelle visualizzazioni delle tabelle, consultare la documentazione dello sviluppatore di Apple su Supporto e trascinamento nelle viste tabella.

Trascina e lascia le migliori pratiche

I contenuti trattati dovrebbero aiutarti a implementare il trascinamento della selezione nelle app, consentendo agli utenti di spostarsi visivamente e in modo interattivo sui contenuti all'interno delle loro app esistenti, oltre che attraverso le app. 

Oltre alle conoscenze tecniche su come implementare il trascinamento della selezione, è imperativo che tu abbia il tempo di pensare a come implementare il drag and drop, seguendo le migliori pratiche sostenute da Apple nelle loro Linee guida dell'interfaccia umana (HIG), in per fornire agli utenti la migliore esperienza utente su iOS 11. 

Per concludere, toccheremo alcuni degli aspetti più importanti da prendere in considerazione, partendo da suggerimenti visivi. Secondo HIG, l'esperienza fondamentale con il trascinamento della selezione è che quando un utente interagisce con alcuni contenuti, i segnali visivi indicano all'utente una sessione di trascinamento attiva, contrassegnata dall'aumento dell'altezza del contenuto, insieme a un badge che indica quando il rilascio è o non è possibile.

Abbiamo già utilizzato questa best practice nei nostri esempi precedenti, quando abbiamo incluso il tableView (_: dropSessionDidUpdate: withDestinationIndexPath :) metodo, che indica se la destinazione di rilascio è una mossa, copia o vietata. È necessario assicurarsi con viste e interazioni personalizzate che si mantenga l'insieme di comportamenti previsti che altre app iOS 11, in particolare le app di sistema, supportano. 

Un altro aspetto importante da considerare è decidere se la tua sessione di trascinamento avrà come risultato una mossa o una copia. Come regola generale, Apple suggerisce che quando lavori all'interno della stessa app, in genere dovrebbe comportare una mossa, mentre ha più senso copiare l'elemento dati mentre stai trascinando tra diverse app. Mentre ci sono delle eccezioni, ovviamente, il principio di base è che dovrebbe avere senso per l'utente, e cosa dovrebbero aspettarsi. 

Dovresti anche pensare in termini di fonti e destinazioni e se abbia senso trascinare qualcosa o no. 

Diamo un'occhiata ad alcune delle utility di sistema di Apple. Le note, ad esempio, consentono di selezionare e trascinare il contenuto del testo in altre posizioni all'interno dell'app o in altre app sull'iPad, tramite schermo diviso. L'app Promemoria ti consente di spostare gli elementi del promemoria da un elenco a un altro elenco. Pensa in termini di funzionalità quando decidi come gli utenti usano i tuoi contenuti. 

La guida di Apple è che tutto il contenuto che è modificabile dovrebbe supportare l'accettazione di contenuti abbandonati, e qualsiasi contenuto che è selezionabile dovrebbe accettare contenuti trascinabili, oltre al supporto di copia e incolla per quei tipi di elementi. Sfruttando le visualizzazioni di testo e i campi di testo standard del sistema, otterrete il supporto per il drag and drop out of the box. 

È inoltre necessario supportare il trascinamento e il rilascio di più elementi, a differenza dei soli singoli elementi di supporto, in cui gli utenti possono utilizzare più di un dito per selezionare contemporaneamente più elementi, raggruppando gli elementi selezionati in un gruppo da rilasciare nelle destinazioni previste. Un esempio di questo in azione è la selezione di più immagini nell'app Foto o più file nell'app File. 

Una linea guida finale è quella di fornire agli utenti la possibilità di invertire un'azione o "annullare" una goccia. Gli utenti sono stati abituati da molto tempo al concetto di annullare un'azione nella maggior parte delle app popolari e il trascinamento della selezione non dovrebbe costituire un'eccezione. Gli utenti dovrebbero avere la certezza di essere in grado di avviare un drag and drop e di essere in grado di invertire tale azione se lasciano cadere l'elemento nella destinazione sbagliata. 

Ulteriori letture

Esistono molte più linee guida di best practice per trascinare e rilasciare le migliori pratiche oltre a ciò che abbiamo visto, incluso come supportare indicatori di indicatori visivi rilasciati, visualizzare azioni fallite e indicatori di progresso per sessioni di trascinamento non istantanee, come i trasferimenti di dati. Consulta le linee guida per l'interfaccia umana iOS di Apple sul drag and drop, per l'elenco completo delle best practice. 

Conclusione

In questo tutorial, hai imparato come arricchire le tue app iOS con il drag and drop, grazie a iOS 11. Lungo il percorso, abbiamo esplorato come abilitare sia le visualizzazioni personalizzate che le viste delle tabelle come sorgenti di trascinamento e destinazioni di rilascio. 

Come parte dell'evoluzione di iOS verso un'interfaccia utente più gestita dai gesti, senza dubbio il drag and drop diventerà rapidamente una funzionalità prevista per gli utenti a livello di sistema e, come tale, anche tutte le app di terze parti dovrebbero essere conformi. E altrettanto importante quanto implementare il drag and drop, è necessario implementarlo correttamente, in modo che diventi una seconda natura per gli utenti, includendo semplicità e funzionalità.

E mentre sei qui, dai uno sguardo ad alcuni dei nostri altri post sullo sviluppo di app per iOS!