Cum să actualizați aplicația pentru iOS 11 Trageți și plasați

Ce veți crea

iOS 11 a ridicat IOS-ul, în special pentru iPad, într-o adevărată platformă multi-tasking, grație Drag and Drop. Acest lucru promite să estompeze limitele dintre aplicații, permițând distribuirea ușoară a conținutului. Profitând de multi-atingere, iOS 11 permite ca conținutul să fie mutat într-un mod natural și intuitiv, apropiindu-se de dispozitivele mobile Apple de paritatea cu bogăția pe care o bucură utilizatorii de desktop și laptop.


Această funcție mult așteptată vă permite să glisați elemente într-o altă locație din aceeași aplicație sau într-o altă aplicație. Aceasta funcționează fie printr-un aranjament cu ecran separat, fie prin doc, folosind un gest continuu. Mai mult decât atât, utilizatorii nu sunt limitați doar la selectarea elementelor unice, dar pot trage mai multe elemente în același timp. Multe aplicații, inclusiv aplicațiile de sistem, precum fotografiile și fișierele, profită de multi-selectarea și glisarea mai multor fișiere.

Obiectivele acestui tutorial

Acest tutorial vă va prezenta drag and drop și apoi aruncați mai adânc în arhitectura și strategia utilizării noului SDK Drag and Drop într-o aplicație bazată pe vizualizare în tabel. Vreau să ajut dezvoltatorii, cum ar fi dvs., să vă conformați aplicațiilor cu comportamentul UI care va deveni standard în viitoarele aplicații iOS. 

În acest tutorial, vom acoperi următoarele:

  • Înțelegerea tragerii și a căderii
  • Implementarea tragerii și căderii într-o vizualizare de tabel 
  • Trageți și aruncați cele mai bune practici

În a doua jumătate a acestui tutorial, vom trece prin pașii practici care permit o aplicație simplă de vizualizare a tabelului pentru a profita de drag and drop, pornind de la unul dintre șabloanele de vizualizare a tablelor implicite de la Apple, disponibile atunci când creați un nou proiect în Xcode 9. Continuați și clonați replica GitHub a tutorialului dacă doriți să urmați.

Cunoașterea presupusă

Acest tutorial presupune că aveți experiență ca dezvoltator de iOS și că ați folosit bibliotecile UIKit în Swift sau Obiectiv-C, inclusiv UITableView, și că aveți o oarecare familiaritate cu delegații și protocoalele.

Înțelegerea tragerii și a căderii

Folosind nomenclatura Apple, un element vizual este tras din locația sursă și scos în locația destinației. Aceasta se numește activitate de tragere, activitatea desfășurându-se fie într-o singură aplicație (iPad și iPhone suportată), fie în două aplicații (disponibile numai pe iPad). 

În timp ce o sesiune de tragere este în desfășurare, atât aplicația sursă, cât și destinația sunt încă active și se execută normal, susținând interacțiunile utilizatorilor. De fapt, spre deosebire de MacOS, iOS suportă mai multe activități de tragere simultană prin utilizarea degetelor multiple. 

Dar să ne concentrăm asupra unui singur articol de drag și asupra modului în care acesta folosește o promisiune ca un contract pentru reprezentările sale de date. 

Trageți articolele ca făgăduințe

Fiecare element de tragere poate fi considerat o promisiune, o reprezentare a datelor conținute care va fi trasă și aruncată de la o sursă la destinație. Elementul de dragare folosește un furnizor de elemente, populându-l registeredTypeIdentifiers cu identificatori de tip uniform, care sunt reprezentări de date individuale pe care se angajează să le livreze destinației dorite, împreună cu o imagine de previzualizare (care este fixată vizual sub punctul de atingere al utilizatorului), după cum se arată mai jos:


Elementul de drag este construit prin UIDragInteractionDelegate de la locația sursă și manipulate în locația destinației prin intermediul UIDropInteractionDelegate. Locația sursei trebuie să fie conformă cu NSItemProviderWriting protocol, iar locația destinației trebuie să fie conformă cu NSItemProviderReading protocol. 

Aceasta este o prezentare de ansamblu de bază a nominalizării unei vizualizări ca element de drag, prin promisiuni. Să vedem cum implementăm o sursă de tragere dintr-o vizualizare, înainte de a stabili destinația drop.

Implementarea unei surse de tragere

Concentrându-ne atenția asupra primei părți a drag & drop-ului - sursa de tragere - trebuie să realizăm următorii pași atunci când utilizatorul inițiază o activitate de tragere:

  1. Conformați vizualizarea la UIDragInterationDelegate protocol.
  2. Declarați elementele de date care vor forma elementul promis, prin dragInteraction (_: itemsForBeginning :)
  3. Utilizați sesiunea de tragere cu elemente de tragere în pregătirea pentru ca utilizatorul să tragă elementele în destinația drop.

Primul lucru pe care trebuie să-l faceți este să vă conformați viziunii dvs. nominalizate UIDragInterationDelegate protocol, prin crearea unui nou UIDragInteraction instanță și asocierea acesteia cu dvs. ViewController's vedere addInteraction proprietate, precum și delegatul său, după cum urmează: 

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

După ce declarați sursa de tragere, continuați să creați un element de tragere, în esență o promisiune de reprezentare a datelor, prin implementarea metodei delegate dragInteraction (_: itemsForBeginning :), pe care sistemul le solicită pentru a returna o matrice din unul sau mai multe elemente de tragere pentru a popula proprietatea articolelor de dragare. Următorul exemplu creează un NSItemProvider dintr-o promisiune a imaginii, înainte de a returna o serie de elemente de date:

func dragInterație (_ interacțiune: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] pază let imaginePromise = imageView.image else return [] // Returând o matrice goală dezactivați tragerea.  let provider = NSItemProvider (obiect: imagePromise) permite item = UIDragItem (itemProvider: provider) returnează [item]

Metoda delegată de mai sus răspunde la o cerere de tragere declanșată atunci când utilizatorul începe să gliseze elementul, cu Gesture Recognizer (UIGestureRecognizer) trimiterea unui mesaj "trageți" înapoi la sistem. Aceasta este ceea ce inițializează inițial "sesiunea de tragere". 

Apoi, vom continua cu implementarea destinației drop, pentru a gestiona matricea elementelor de tragere inițiate în sesiune.

Implementarea unei Destinații Drop

De asemenea, pentru a vă conforma vizualizării nominalizate pentru a accepta și a consuma date ca parte a destinației drop, va trebui să parcurgeți următorii pași:

  1. Instantiate a DropInteraction.
  2. Declarați tipurile de elemente de date (dacă există) pe care le veți accepta, utilizând dropInteraction (_: canHandle :).
  3. Implementați o propunere de drop folosind dropInteraction (_: sessionDidUpdate :) metode de protocol, în care se precizează dacă veți copia, mutați, refuzați sau anulați sesiunea.
  4. În cele din urmă, consumați elementele de date utilizând dropInteraction (_: performDrop :) metoda protocolului.

Așa cum am configurat vizualizarea noastră pentru a permite tragerea, vom configura simetric vizualizarea noastră nominalizată pentru a accepta elemente abandonate dintr-o sesiune de tragere, utilizând UIDropinteractionDelegate și punerea în aplicare a acesteia DropInteraction metoda delegat:

lasă dropInteraction = UIDropInteraction (delegate: dropInteractionDelegate) view.addInteraction (dropInteraction)

Pentru a desemna dacă o vizualizare este capabilă să accepte elemente de tragere sau refuză, implementăm dropInteraction (_: canHandle :) metoda protocolului. Următoarea metodă permite vizualizării noastre să spună sistemului dacă poate accepta elementele, afirmând tipul de obiecte pe care le poate primi - în acest caz UIImages.

func dropInteraction (_ interacțiune: UIDropInteraction, sesiune canHandle: UIDropSession) -> Bool // Explicit afișează tipul elementului drop drop acceptabil aici return session.canLoadObjects (ofClass: UIImage.self)

Dacă obiectul de vizualizare nu acceptă nicio interacțiune a căderii, ar trebui să returnați false din această metodă. 

Apoi, obligați o propunere de drop pentru a accepta datele din sesiunea de scădere. Deși aceasta este o metodă opțională, este foarte recomandat să implementați această metodă, deoarece oferă indicații vizuale cu privire la faptul dacă această picătură va duce la copierea elementului, mutarea acestuia sau la respingerea totală a căderii. Prin implementarea dropInteraction (_: sessionDidUpdate :) protocol, care returnează a UIDropProposal, indicați tipul de propunere folosind tipul de enumerare specifică a operației (UIDropOperation). Tipurile valide pe care le puteți returna sunt:

  • Anulare
  • interzis
  • copie
  • mișcare
func dropInteraction (_ interacțiune: UIDropInteraction, sessionDidUpdate sesiune: UIDropSession) -> UIDropProposal // Semnal la sistemul pe care îl veți muta elementul din aplicația sursă (de asemenea, puteți specifica .copy pentru copiere, spre deosebire de mutare) operație: .move)

În sfârșit, pentru a consuma conținutul elementului de date din locația de destinație, implementați dropInteraction (_: performDrop :) metoda de protocol în coada de fundal (mai degrabă decât în ​​coada principală - aceasta asigură răspunsul). Acest lucru este ilustrat mai jos: 

func dropInteraction (_ interacțiune: UIDropInteraction, performăDrop sesiune: UIDropSession) // Consumați UIImage drag drag articole session.loadObjects (ofClass: UIImage.self) elementele în let imagini = elemente ca! [UIImage] auto.imageView.image = imagini.first

Am demonstrat cum veți implementa drag and drop într-o vizualizare personalizată, deci acum să trecem la partea practică a acestui tutorial și să implementăm drag and drop pe o aplicație cu o vizualizare de tabel.

Implementarea tragerii și căderii într-o vizualizare de tabel

Până acum, am discutat despre modul de implementare a drag and drop în vizualizările personalizate, dar Apple a făcut de asemenea ușor să măriți vizualizările de tabel și vederile de colectare cu drag and drop. În timp ce câmpurile de text și vizualizările acceptă în mod automat tragerea și iesirea din cutie, tabelele și vizualizările colecției expun metode specifice, delegați și proprietăți pentru personalizarea comportamentelor lor de tragere și plasare. Vom analiza acest lucru în scurt timp.

Începeți prin crearea unui nou proiect în Xcode 9, asigurându-vă că selectați Aplicația Master-Detail din fereastra șablonului:

Înainte de a începe să lucrați la restul pașilor, continuați și construiți și executați proiectul și jucați puțin împreună cu el. Veți vedea că generează o nouă dată de marcare a timpului când selectați plus (+). Vom îmbunătăți această aplicație, permițând utilizatorului să gliseze și să comande marcajele de timp. 

Drag and drop este acceptat în vizualizările de tabelă (precum și în colecții) prin intermediul API-urilor specializate care permit tragerea și detașarea cu rânduri, prin adaptarea tabelului nostru pentru a adopta atât UITableViewDragDelegate și UITableViewDropDelegate protocoale. Deschideți MasterViewController.swift fișier și adăugați următoarele la viewDidLoad () metodă:

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

Așa cum am făcut și cu vizualizările personalizate, trebuie să rezolvăm noua sesiune de tragere atunci când utilizatorul trage un rând selectat sau mai multe rânduri / selecții. Facem acest lucru cu metoda delegat tableView (_: itemsForBeginning: la :). În cadrul acestei metode, fie returnați o matrice populată care începe tragerea rândurilor selectate, fie o matrice goală pentru a împiedica utilizatorul să tragă conținutul din acea cale index. 

Adăugați următoarea metodă la dvs. MasterViewController.swift fişier:

func tableView (_tableView: UITableView, itemsFor sesiunea de început: UIDragSession, la indexPath: IndexPath) -> [UIDragItem] let dateItem = self.objects [indexPath.row] ca! String lasa data = dateItem.data (folosind: .utf8) sa lase itemProvider = NSItemProvider () itemProvider.registerDataRepresentation (pentruTypeIdentifier: kUTTypePlainText ca String, visibility: .all) return [UIDragItem itemProvider: itemProvider)]

Unele dintre codurile adăugate ar trebui să vă fie deja cunoscute din secțiunea anterioară, dar, în esență, ceea ce facem este să creați un element de date de la obiectul selectat, să-l împachetați într-o NSItemProvider, și întoarce-o într-o DragItem

Dacă ne îndreptăm atenția lângă activarea sesiunii de drop, continuați cu adăugarea următoarelor două metode:

func tableView (_ tableView: UITableView, sesiune canHandle: UIDropSession) -> Bool return session.canLoadObjects (ofClass: NSString.self) func tableView (_tableView: UITableView, dropSessionDidUpdate sesiune: UIDropSession, DestinationIndexPath destinationIndexPath: UITableViewDropProposal if tableView.hasActiveDrag dacă session.items.count> 1 retur UITableViewDropProposal (operațiune: .cancel) altceva return UITableViewDropProposal (funcționare: .move, intent: .insertAtDestinationIndexPath) else return UITableViewDropProposal (operațiune:. copie, intenție: .insertAtDestinationIndexPath)

Prima metodă indică sistemului că poate gestiona tipurile de date String ca parte a sesiunii sale de drop. A doua metodă a delegatului, tableView (_: dropSessionDidUpdate: withDestinationIndexPath :), urmărește localizarea potențială a căderii, notificând metoda cu fiecare schimbare. De asemenea, afișează feedback vizual pentru a permite utilizatorului să știe dacă o anumită locație este interzisă sau acceptabilă, folosind un tactic mic cu pictograme vizuale. 

În cele din urmă, ne ocupăm de cădere și consumăm elementul de date, sunând tableView (_: performDropWith :), preluarea rândului de elemente de date tras, actualizarea sursei de date din tabelul de vizualizare și introducerea rândurilor necesare în tabel.

func tableView (_ tableView: UITableView, executaDropWith coordonator: UITableViewDropCoordinator) la destinațieIndexPath: IndexPath dacă indexPath = coordinator.destinationIndexPath destinationIndexPath = indexPath altceva // Obțineți ultima cale index a vizualizării tabelului. (secțiunea: secțiune: secțiune) coordinator.session.loadObjects (din Clasa: NSString.self) items in // Consume trageți elementele. permiteți stringItems = elemente ca! [String] var indexPaths = [IndexPath] () pentru (index, element) în stringItems.enumerated () let indexPath = IndexPath (rând: destinationIndexPath.row + index, sectionIndexPath.section) self.objects.insert , la: indexPath.row) indexPaths.append (indexPath) tableView.insertRows (la: indexPaths, with: .automatic)

Citirea în continuare

Pentru mai multe informații despre susținerea drag and drop în vizualizările de tabelă, consultați propria documentație de dezvoltare a propriei dezvoltatori de la Apple privind Suportul Drag and Drop în vizualizările tabelului.

Trageți și aruncați cele mai bune practici

Conținutul pe care l-am acoperit ar trebui să vă ajute să implementați drag and drop în aplicațiile dvs., permițând utilizatorilor să se deplaseze vizual și interactiv în jurul conținutului din aplicațiile existente, precum și între aplicații. 

Pe lângă cunoștințele tehnice despre implementarea tragerii și a abandonului, este totuși necesar să vă gândiți la modul în care veți implementa funcția drag and drop, urmând cele mai bune practici recomandate de Apple în Ghidul pentru interfața umană (HIG), în pentru a oferi utilizatorilor cea mai bună experiență de utilizare a iOS 11. 

Pentru a încheia, vom aborda câteva din cele mai importante aspecte pe care trebuie să le analizăm, începând cu indicațiile vizuale. Conform HIG, experiența fundamentală cu drag and drop este că atunci când un utilizator interacționează cu un anumit conținut, indicațiile vizuale indică utilizatorului o sesiune de tracțiune activă, notată prin creșterea elementului de conținut, împreună cu o insignă care indică când este abandonat sau nu este posibil.

Am folosit deja această bună practică în exemplele noastre anterioare, când am inclus tableView (_: dropSessionDidUpdate: withDestinationIndexPath :) , indicând dacă destinația picăturii este o mișcare, copie sau interzisă. Ar trebui să vă asigurați că opiniile și interacțiunile personalizate vă mențin setul așteptat de comportamente pe care alte aplicații iOS 11, în special aplicațiile de sistem, le suportă. 

Un alt aspect important care trebuie luat în considerare este să decideți dacă sesiunea de tragere va avea ca rezultat o mișcare sau o copie. Ca regulă generală, Apple sugerează că atunci când lucrați în cadrul aceleiași aplicații, aceasta ar trebui să aibă drept rezultat o mișcare, în timp ce este mai logic să copiați elementul de date atunci când trageți între diferite aplicații. Deși există excepții, desigur, principiul care stau la baza este că ar trebui să aibă sens pentru utilizator și ce așteaptă să se întâmple. 

De asemenea, ar trebui să vă gândiți la surse și destinații și dacă are sens să trageți ceva sau nu. 

Să aruncăm o privire la unele dintre utilitățile de sistem ale Apple. Note, de exemplu, vă permite să selectați și să trageți conținutul textului în alte locații din aplicație sau în alte aplicații de pe iPad, prin intermediul unui ecran separat. Aplicația Mementouri vă permite să mutați elemente de reamintire dintr-o listă în alta. Gândiți-vă în termeni de funcționalitate atunci când decideți cum utilizatorii utilizează conținutul dvs.. 

Ghidul Apple este că întregul conținut care poate fi editat ar trebui să accepte acceptarea conținutului abandonat, iar orice conținut care poate fi selectat trebuie să accepte conținut drabit, în plus față de copierea și lipirea pentru acele tipuri de elemente. Prin folosirea vizualizărilor de text standard ale sistemului și a câmpurilor de text, veți primi suport pentru tragere și ieșire din cutie. 

De asemenea, ar trebui să acceptați drag and drop în mai multe elemente, spre deosebire de elementele unice care acceptă, prin care utilizatorii pot folosi mai mult de un deget pentru a selecta simultan mai multe elemente, pentru a plasa elementele selectate într-un grup pentru a fi scoase în destinațiile lor. Un exemplu în această acțiune este selectarea mai multor imagini din aplicația Photos sau mai multe fișiere din aplicația Fișiere. 

O orientare finală este de a oferi utilizatorilor posibilitatea de a inversa o acțiune sau de a "anula" o scădere. Utilizatorii au fost obișnuiți de foarte mult timp cu conceptul de anulare a unei acțiuni în majoritatea aplicațiilor populare, iar drag and drop nu ar trebui să fie o excepție. Utilizatorii ar trebui să aibă încrederea că vor putea să inițieze o tragere și să renunțe și să poată inversa acea acțiune dacă scot elementul într-o destinație greșită. 

Citirea în continuare

Există multe linii directoare privind cele mai bune practici dincolo de ceea ce ne-am uitat, inclusiv modul în care se acceptă indicațiile vizuale ale indicatorilor vizați, afișarea acțiunilor eșuate abandonate și indicatorii de progres pentru sesiuni de tragere non-instant, cum ar fi transferurile de date. Consultați Ghidul de interfață umană iOS de la Apple pentru drag and drop, pentru lista completă a celor mai bune practici. 

Concluzie

În acest tutorial, ați învățat cum să vă îmbogățiți aplicațiile iOS cu drag și drop, grație iOS 11. Pe parcurs, am explorat cum să activați vizualizările personalizate și vizualizările de tabel ca surse de tragere și destinații de cădere. 

Ca parte a evoluției iOS spre o interfață de utilizator mai gestă, fără îndoială, drag and drop va deveni rapid o caracteristică așteptată pentru utilizatorii de sistem și, ca atare, toate aplicațiile terțelor părți trebuie, de asemenea, să se conformeze. Și la fel de important ca implementarea drag and drop, va trebui să o implementați corect, astfel încât să devină oa doua natură pentru utilizatori, care să cuprindă simplitatea și funcționalitatea.

Și în timp ce sunteți aici, verificați câteva dintre celelalte postări ale noastre privind dezvoltarea aplicațiilor iOS!

Cod