iOS 11 har forhøyet iOS, spesielt for iPad, til en sann plattform med flere oppgaver, takket være Drag og Drop. Dette lover å utrydde grensene mellom apper, slik at innholdet kan deles enkelt. IOS 11 gjør det mulig å flytte innholdet på en naturlig og intuitiv måte, noe som gjør at Apples mobilenheter blir nærmere paritet med den rikdom som nytes av stasjonære og bærbare brukere.
Denne etterlengtede funksjonen lar deg dra elementer til et annet sted i samme program, eller til et annet program. Dette fungerer enten via en delt skjerm eller via bryggen, ved hjelp av en kontinuerlig gest. Videre er brukerne ikke begrenset til å bare velge enkeltartikler, men kan trekke flere elementer samtidig. Mange apper, inkludert systemprogrammer som bilder og filer, utnytter flere valg og drar flere filer.
Denne opplæringen vil introdusere deg til å dra og slippe, og deretter dykke dypere inn i arkitekturen og strategien for å bruke den nye Dra og slipp-SDK-en i en tabellutsiktdrevet app. Jeg vil hjelpe utviklere som deg selv til å tilpasse appene dine til den nye brukergrensesnittet som vil bli standard i fremtidige iOS-apper.
I denne opplæringen vil vi dekke følgende:
I andre halvdel av denne opplæringen vil vi gå gjennom de praktiske trinnene for å muliggjøre en enkel tabellvisningsprogram for å dra nytte av dra og slipp, som starter med en av Apples standard tabellvisningsmaler som er tilgjengelige når du oppretter et nytt prosjekt i Xcode 9. Fortsett og klone opplæringen GitHub repo hvis du vil følge med.
Denne opplæringen forutsetter at du har erfaring som en iOS-utvikler og har brukt UIKit-biblioteker i Swift eller Objective-C, inkludert UITableView
, og at du har noen kjennskap til delegater og protokoller.
Ved å bruke Apples nomenklatur, blir et visuelt element trukket fra kildeplasseringen og falt på destinasjonsstedet. Dette kalles en draaktivitet, hvor aktiviteten enten foregår i en enkelt app (iPad og iPhone støttet), eller på tvers av to apper (kun tilgjengelig på iPad).
Mens en drassesjon er i gang, er både kilden og destinasjonsappene fortsatt aktive og går som normalt, og støtter brukerinteraksjoner. Faktisk, i motsetning til macOS, støtter iOS flere samtidige dragaktiviteter ved å bruke flere fingre.
Men la oss fokusere på et enkelt trekkobjekt, og hvordan det bruker et løfte som en kontrakt for sine datapresentasjoner.
Hver dra-element kan betraktes som et løfte, en inneholdt datarepresentasjon som vil bli slept og falt fra en kilde til bestemmelsesstedet. Dra-elementet bruker en vareleverandør, som fyller sin registeredTypeIdentifiers
med ensartede typeidentifikatorer, som er individuelle datapresentasjoner som den vil forplikte seg til å levere til den tilsiktede destinasjonen sammen med et forhåndsvisningsbilde (som er festet under brukerens berøringspunkt visuelt), som illustrert nedenfor:
Dra-elementet er konstruert gjennom UIDragInteractionDelegate
fra kildeplasseringen og håndtert på destinasjonsstedet via UIDropInteractionDelegate
. Kildelokasjonen må samsvare med NSItemProviderWriting
protokollen, og destinasjonsstedet må samsvare med NSItemProviderReading
protokollen.
Det er en grunnleggende oversikt over å nominere en visning som et dragelement, gjennom løfter. La oss se hvordan vi implementerer en dragkilde fra en visning, før du oppretter drop-destinasjonen.
Fokusere vår oppmerksomhet på den første delen av dra og slipp-drakilden - vi må utføre følgende trinn når brukeren starter en draaktivitet:
UIDragInterationDelegate
protokollen.dragInteraction (_: itemsForBeginning :)
. Det første du må gjøre er å tilpasse din nominert visning til UIDragInterationDelegate
protokoll, ved å opprette en ny UIDragInteraction
forekommer og forbinder det med din ViewController
synspunkt er addInteraction
eiendom samt delegat, som følger:
la draInteraction = UIDragInteraction (delegate: dragInteractionDelegate) view.addInteraction (dragInteraction)
Når du har erklært drakilden din, fortsetter du med å opprette et draelement, i hovedsak et løfte om datarrepresentasjon, ved å implementere delegatemetoden dragInteraction (_: itemsForBeginning :)
, som systemet ringer for å returnere en rekke av en eller flere draelementer for å fylle ut egenskapen for drassesjonens gjenstander. Følgende eksempel oppretter en NSItemProvider
fra et bilde løfte, før du returnerer en rekke dataelementer:
funk dragInteraction (_ interaksjon: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] guard la imagePromise = imageView.image else return [] // Ved å returnere et tomt array du deaktiverer å dra. la leverandør = NSItemProvider (objekt: imagePromise) la element = UIDragItem (itemProvider: leverandør) returnere [item]
Delegemetoden ovenfor svarer på en draforespørsel utløst når brukeren begynner å dra elementet, med Gesture Recognizer (UIGestureRecognizer
) sender en "drastart" -melding tilbake til systemet. Dette er hva som i utgangspunktet initierer "drassesjonen".
Deretter fortsetter vi med å implementere drop-destinasjonen, for å håndtere mengden av draelementer som er startet i sesjonen.
På samme måte for å tilpasse din nominert visning for å godta og forbruke data som en del av drop-destinasjonen, må du gjøre følgende:
DropInteraction
.dropInteraction (_: canHandle :)
.dropInteraction (_: sessionDidUpdate :)
protokollmetode, og angir om du vil kopiere, flytte, nekte eller kansellere økten.dropInteraction (_: performDrop :)
protokollmetode.Akkurat som vi konfigurerte vårt syn for å aktivere dra, vil vi symmetrisk konfigurere vår nominert visning for å godta slippte elementer fra en drassesjon, ved hjelp av UIDropinteractionDelegate
og gjennomføre sin DropInteraction
delegere metode:
la dropInteraction = UIDropInteraction (delegate: dropInteractionDelegate) view.addInteraction (dropInteraction)
For å angi om en visning er i stand til å akseptere dragenheter eller nekter, implementerer vi dropInteraction (_: canHandle :)
protokollmetode. Følgende metode lar våre synspunkter fortelle systemet om det kan akseptere elementene ved å angi hvilken type objekter den kan motta, i dette tilfellet UIImages.
func dropInteraction (_ interaksjon: UIDropInteraction, canHandle-økt: UIDropSession) -> Bool // Angiv eksplisitt det akseptable dråpeelementet her returnere session.canLoadObjects (ofClass: UIImage.self)
Hvis visningen objektet ikke aksepterer noen dråpevirkninger, bør du returnere falsk fra denne metoden.
Deretter bind en dråpeforslag for å akseptere data fra drop-økten. Selv om dette er en valgfri metode, anbefales det sterkt at du implementerer denne metoden, siden det gir visuelle tegn på om dråpen vil resultere i å kopiere varen, flytte den, eller om dråpen vil bli nektet helt. Ved å implementere dropInteraction (_: sessionDidUpdate :)
protokollmetode, som returnerer a UIDropProposal
, Du angir forslagstypen ved hjelp av den spesifikke operasjonstellingstypen (UIDropOperation
). De gyldige typene du kan returnere er:
Avbryt
forbudt
kopiere
bevege seg
funk dropInteraction (_ interaksjon: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal // Signal til systemet som du vil flytte elementet fra kildeappen (du kan også oppgi .kopi for å kopiere i motsetning til flytting) returnere UIDropProposal ( operasjon: .move)
Og til slutt, for å konsumere innholdet i dataelementet i destinasjonsstedet, implementerer du dropInteraction (_: performDrop :)
protokollmetode i bakgrunnskøen (i stedet for i hovedkøen-dette sikrer responsevne). Dette illustreres nedenfor:
func dropInteraction (_ interaksjon: UIDropInteraction, performDrop session: UIDropSession) // Forbruker UIImage dra elementer session.loadObjects (ofClass: UIImage.self) elementer i la bilder = elementer som! [UIImage] self.imageView.image = images.first
Vi har demonstrert hvordan du implementerer dra og slipp i en egendefinert visning, så la oss nå gå videre til den praktiske delen av denne opplæringen og implementere dra og slipp på en app med en tabellvisning.
Så langt har vi diskutert hvordan du implementerer dra og slipp i tilpassede visninger, men Apple har også gjort det enkelt å øke tabellvisninger og samlingsvisninger med dra og slipp. Mens tekstfelt og visninger automatisk støtter dra og slippe ut av boksen, viser tabell og samling visninger spesifikke metoder, delegater og egenskaper for å tilpasse deres dra og slippe atferd. Vi tar en titt på dette snart.
Start med å lage et nytt prosjekt i Xcode 9, slik at du velger Master-detaljapp fra malvinduet:
Før du begynner å jobbe med resten av trinnene, fortsett å bygge og kjøre prosjektet og leke med det litt. Du får se at det genererer en ny tidsstempeldato når du velger pluss (+) -knappen. Vi skal forbedre denne appen ved å la brukeren dra og bestille tidsstemplene.
Dra og slipp støttes i tabellvisninger (samt samlinger) gjennom spesialiserte APIer som gjør det mulig å dra og slippe med rader, ved å tilpasse tabelloversikten for å vedta både UITableViewDragDelegate
og UITableViewDropDelegate
protokoller. Åpne opp MasterViewController.swift fil og legg til følgende til viewDidLoad ()
metode:
overstyr func viewDidLoad () super.viewDidLoad () ... self.tableView.dragDelegate = self self.tableView.dropDelegate = selv ...
Som vi gjorde med tilpassede visninger, må vi håndtere den nye draksesjonen når brukeren drar en valgt rad eller flere rader / valg. Vi gjør dette med delegatemetoden Tableview (_: itemsForBeginning: i :)
. Innenfor denne metoden returnerer du enten et populert array som begynner å dra de valgte radene, eller en tom rekkefølge for å hindre at brukeren drar innhold fra den spesifikke indeksbanen.
Legg til følgende metode for din MasterViewController.swift fil:
func tableView (_ tableView: UITableView, itemsForBeginning session: UIDragSession, på indexPath: IndexPath) -> [UIDragItem] la dateItem = self.objects [indexPath.row] as! String la data = dateItem.data (using: .utf8) la itemProvider = NSItemProvider () itemProvider.registerDataRepresentation (forTypeIdentifier: kUTTypePlainText som streng, synlighet: .all) ferdigstillelse i ferdigstillelse (data, null) return null returnere [UIDragItem itemProvider: itemProvider)]
Noen av koden som er lagt til, burde allerede være kjent for deg fra forrige del, men i hovedsak hva vi gjør er å lage et datapunkt fra det valgte objektet, pakk det inn i en NSItemProvider
, og returner den i a DragItem
.
Gjør oppmerksomheten ved siden av å aktivere drop-økten, fortsett med å legge til følgende to metoder:
func tableView (_ tableView: UITableView, canHandle økt: UIDropSession) -> Bool return session.canLoadObjects (ofClass: NSString.self) func tableView (_ tableView: UITableView, dropSessionDidUpdate økt: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal hvis tableView.hasActiveDrag hvis session.items.count> 1 return UITableViewDropProposal (operasjon: .cancel) else return UITableViewDropProposal (operasjon: .move, intent: .insertAtDestinationIndexPath) else return UITableViewDropProposal (operasjon:. kopi, hensikt: .insertAtDestinationIndexPath)
Den første metoden forteller systemet at det kan håndtere String-datatyper som en del av drop-økten. Den andre delegatemetoden, Tableview (_: dropSessionDidUpdate: withDestinationIndexPath :)
, sporer potensiell dråpeplass, og underretter metoden med hver endring. Den viser også visuell tilbakemelding for å la brukeren få vite om et bestemt sted er forbudt eller akseptabelt, ved hjelp av et lite visuelt ikonkurs.
Til slutt håndterer vi dråpen og forbruker dataelementet, ringer Tableview (_: performDropWith :)
, henter den raste dataelementraden, oppdaterer tabellkildens datakilde og setter de nødvendige radene inn i bordet.
func tableView (_ tableView: UITableView, performDropWith koordinator: UITableViewDropCoordinator) la destinationIndexPath: IndexPath hvis la indexPath = coordinator.destinationIndexPath destinationIndexPath = indexPath else // Få siste indeksbane i tabellvisning. la avsnitt = tableView.numberOfSections - 1 la row = tableView.numberOfRows (inSection: section) destinationIndexPath = IndexPath (rad: rad, seksjon: seksjon) coordinator.session.loadObjects (ofClass: NSString.self) elementer i // Forbruker dra elementer. la stringItems = elementer som! [String] var indexPaths = [IndexPath] () for (indeks, element) i stringItems.enumerated () la indexPath = IndexPath (rad: destinationIndexPath.row + indeks, seksjon: destinationIndexPath.section) self.objects.insert , på: indexPath.row) indexPaths.append (indexPath) tableView.insertRows (ved: indexPaths, med: .automatic)
Hvis du vil ha mer informasjon om å støtte dra og slippe i tabellvisningen, kan du se Apples egen utvikler dokumentasjon om Støtte dra og slipp i tabellvisninger.
Innholdet vi dekket skal hjelpe deg med å implementere dra og slipp i appene dine, slik at brukerne kan bevege seg visuelt og interaktivt rundt innholdet i de eksisterende appene sine, samt på tvers av apper.
Sammen med teknisk kunnskap om hvordan du implementerer dra og slipp, er det imidlertid viktig at du tar deg tid til å vurdere hvordan du implementerer dra og slipp, etter de beste praksiser som Apple foreslo i deres retningslinjer for menneskelig grensesnitt (HIG), i For å gi brukerne den best mulige iOS 11 brukeropplevelsen.
Å pakke opp, vi berører noen av de viktigste aspektene å vurdere, med utgangspunkt i visuelle signaler. Ifølge HIG er den grunnleggende erfaringen med å dra og slippe at når en bruker samhandler med noe innhold, viser visuelle signaler til brukeren en aktiv drassesjon, betegnet ved at innholdselementet stiger, sammen med et merke for å indikere når slippet er eller er ikke mulig.
Vi har allerede brukt denne beste praksis i våre tidligere eksempler, da vi inkluderte Tableview (_: dropSessionDidUpdate: withDestinationIndexPath :)
metode, som angir om destinasjonsdestinasjonen er et trekk, kopi eller forbudt. Du bør sikre at tilpassede visninger og interaksjoner som du opprettholder det forventede settet av atferd som andre iOS 11-apper, spesielt systemprogrammer, støtter.
Et annet viktig aspekt å vurdere er å avgjøre om drassesjonen din resulterer i et trekk eller en kopi. Som en generell tommelfingerregel foreslår Apple at når du arbeider innenfor samme app, bør det generelt føre til et trekk, mens det er mer sanselig å kopiere dataelementet når du drar mellom forskjellige apper. Selv om det er unntak, er selvsagt det underliggende prinsippet at det skal være fornuftig for brukeren, og hva de forventer skal skje.
Du bør også tenke når det gjelder kilder og destinasjoner, og om det er fornuftig å dra noe eller ikke.
La oss ta en titt på noen av Apples egne systemverktøy. Notater, for eksempel, lar deg velge og dra tekstinnhold til andre steder i appen, eller over til andre apps på iPad, via delt skjerm. Påminnelses-appen lar deg flytte påminnelseselementer fra en liste til en annen liste. Tenk når det gjelder funksjonalitet når du bestemmer deg for hvordan brukerne bruker innholdet ditt.
Apples veiledning er at alt innhold som kan redigeres, bør støtte å godta slippet innhold, og alt innhold som kan velges, bør akseptere dragerbart innhold, i tillegg til å støtte kopiere og lime for disse elementene. Ved å utnytte standard systemtekstvisninger og tekstfelt får du støtte for å dra og slippe ut av boksen.
Du bør også støtte trekk og slipp av flere elementer, i motsetning til bare å støtte enkeltelementer, der brukere kan bruke mer enn en finger til å velge flere elementer samtidig, stabling de valgte elementene i en gruppe som skal slippes inn i de planlagte destinasjonene. Et eksempel på dette er å velge flere bilder i Bilder-appen, eller flere filer i Fil-appen.
En endelig retningslinje er å gi brukerne muligheten til å reversere en handling, eller "angre" en dråpe. Brukere har lenge vært vant til konceptet om å angre en handling i de fleste av de populære appene, og dra og slipp burde ikke være noe unntak. Brukere bør ha tillit til å kunne starte en dra og slippe og kunne reversere denne handlingen hvis de slipper elementet i feil destinasjon.
Det er mange flere dra og slippe retningslinjer for beste praksis utover det vi har sett på, blant annet hvordan du støtter tapt visuelle indikator-signaler, viser mislykkede droppehandlinger og fremdriftsindikatorer for ikke-øyeblikkelige drakter, for eksempel dataoverføringer. Rådfør deg med Apples retningslinjer for iOS-grensesnitt om dra og slipp, for den komplette listen over beste praksis.
I denne opplæringen har du lært hvordan du beriker iOS-appene dine med dra og slipp, med IOS 11. Underveis utforsket vi hvordan du aktiverer både tilpassede visninger og tabellvisninger som drakilder og slett destinasjoner.
Som en del av IOS-utviklingen mot et mer gest-drevet brukergrensesnitt, vil dra og slipp uten tvil raskt bli en forventet funksjon for brukere over hele systemet, og som sådan bør alle tredjepartsappene også være i overensstemmelse. Og like viktig som å implementere dra og slipp, må du implementere det riktig, slik at det blir den andre naturen til brukerne, som omfatter enkelhet og funksjonalitet.
Og mens du er her, sjekk ut noen av våre andre innlegg på IOS app utvikling!