iOS 11 heeft iOS, met name voor de iPad, met Drag and Drop tot een echt multi-tasking-platform verheven. Dit belooft de grenzen tussen apps te vervagen, zodat content eenvoudig kan worden gedeeld. IOS 11 maakt gebruik van multi-aanrakingen en zorgt ervoor dat inhoud op een natuurlijke en intuïtieve manier kan worden verplaatst, waardoor de mobiele apparaten van Apple dichter bij pariteit komen met de rijkdom van desktop- en laptopgebruikers.
Met deze langverwachte functie kun je items naar een andere locatie in dezelfde app of naar een andere applicatie slepen. Dit werkt via een gesplitst scherm of via het dock, met behulp van een continu gebaar. Bovendien zijn gebruikers niet beperkt tot het selecteren van afzonderlijke items, maar kunnen ze tegelijkertijd meerdere items slepen. Veel apps, waaronder systeem-apps zoals Foto's en Bestanden, profiteren van multi-selectie en het slepen van meerdere bestanden.
In deze zelfstudie leert u slepen en neerzetten en duikt u dieper in de architectuur en de strategie van het gebruik van de nieuwe SDK met slepen en neerzetten in een app met door de tafelweergave aangedreven apps. Ik wil ontwikkelaars zoals uzelf helpen om uw apps te conformeren aan het opkomende UI-gedrag dat standaard wordt in toekomstige iOS-apps.
In deze zelfstudie behandelen we het volgende:
In de tweede helft van deze zelfstudie zullen we de praktische stappen doorlopen om een eenvoudige tabelweergave-app in staat te stellen te profiteren van slepen en neerzetten, te beginnen met een van de standaard tabelweergavesjablonen van Apple die beschikbaar is wanneer u een nieuw project in Xcode maakt 9. Ga je gang en klop de GitHub-repo van de tutorial als je deze wilt volgen.
Deze tutorial gaat ervan uit dat je ervaring hebt als iOS-ontwikkelaar en hebt UIKIT-bibliotheken gebruikt in Swift of Objective-C, inclusief UITableView
, en dat je enige bekendheid hebt met afgevaardigden en protocollen.
Met de nomenclatuur van Apple wordt een visueel item van de bronlocatie gesleept en op de bestemmingslocatie neergezet. Dit wordt een sleepactiviteit genoemd, waarbij de activiteit plaatsvindt in één app (iPad en iPhone ondersteund), of in twee apps (alleen beschikbaar op iPad).
Terwijl een sleepsessie bezig is, zijn zowel de bron- als de bestemmings-apps nog steeds actief en worden ze als normaal uitgevoerd, waardoor gebruikersinteracties worden ondersteund. In tegenstelling tot macOS ondersteunt iOS meerdere gelijktijdige sleepactiviteiten door meerdere vingers te gebruiken.
Maar laten we ons richten op één enkel item en hoe het een belofte gebruikt als een contract voor zijn gegevensrepresentaties.
Elk item kan worden beschouwd als een belofte, een ingesloten gegevensweergave die van een bron naar zijn bestemming wordt gesleept en weggelaten. Het sleepitem gebruikt een itemprovider en vult deze in registeredTypeIdentifiers
met uniforme typeaanduidingen, die afzonderlijke gegevensrepresentaties zijn die worden toegewezen aan de beoogde bestemming, samen met een voorbeeldafbeelding (die visueel wordt vastgemaakt onder het aanraakpunt van de gebruiker), zoals hieronder geïllustreerd:
Het sleepitem is geconstrueerd via de UIDragInteractionDelegate
van de bronlocatie en behandeld op de doellocatie via de UIDropInteractionDelegate
. De bronlocatie moet voldoen aan de NSItemProviderWriting
protocol, en de locatie van de bestemming moet overeenkomen met de NSItemProviderReading
protocol.
Dat is een basisoverzicht van het nomineren van een weergave als een sleepitem, door middel van beloften. Laten we eens kijken hoe we een slepen-bron implementeren vanuit een weergave voordat de bestemmingsbestemming wordt vastgesteld.
Door onze aandacht te richten op het eerste deel van het slepen en neerzetten, de sleepbron, moeten we de volgende stappen uitvoeren wanneer de gebruiker een sleepactiviteit initieert:
UIDragInterationDelegate
protocol.dragInteraction (_: itemsForBeginning :)
. Het eerste dat u moet doen is uw genomineerde weergave aanpassen aan de UIDragInterationDelegate
protocol, door een nieuwe te maken UIDragInteraction
bijvoorbeeld en associeer het met uw ViewController
's uitzicht is addInteraction
eigendom alsmede zijn afgevaardigde, als volgt:
let dragInteraction = UIDragInteraction (delegate: dragInteractionDelegate) view.addInteraction (dragInteraction)
Na het declareren van je sleepbron, ga je verder met het maken van een sleepitem, in wezen een belofte van gegevensrepresentatie, door de gedelegeerde methode te implementeren dragInteraction (_: itemsForBeginning :)
, die het systeem aanroept om een array van een of meer sleepitems te retourneren om de eigenschap items van de sleepsessie te vullen. In het volgende voorbeeld wordt een NSItemProvider
van een imagobelofte, voordat een array met gegevensitems wordt geretourneerd:
func dragInteraction (_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] guard let imagePromise = imageView.image else return [] // Door een lege array te retourneren, schakel je het slepen uit. laat provider = NSItemProvider (object: imagePromise) laat item = UIDragItem (itemProvider: provider) retourneer [item]
De gedelegeerde methode hierboven reageert op een sleepaanvraag die wordt geactiveerd wanneer de gebruiker begint met het slepen van het item, met de Gesture Recognizer (UIGestureRecognizer
) verzenden van een "sleep gestart" bericht terug naar het systeem. Dit is wat in wezen de "sleepsessie" initialiseert.
Vervolgens gaan we verder met het implementeren van de bestemmingsbestemming, om de array met sleepitems die in de sessie is gestart, af te handelen.
Evenzo, om uw genomineerde weergave te conformeren om gegevens te accepteren en te gebruiken als onderdeel van de dropbestemming, moet u de volgende stappen uitvoeren:
DropInteraction
.dropInteraction (_: canHandle :)
.dropInteraction (_: sessionDidUpdate :)
protocolmethode, met vermelding of u de sessie kopieert, verplaatst, weigert of annuleert.dropInteraction (_: performDrop :)
protocol methode.Net zoals we onze weergave hebben geconfigureerd om verslepen in te schakelen, zullen we symmetrisch onze genomineerde weergave configureren om vallende items van een sleepsessie te accepteren, met behulp van de UIDropinteractionDelegate
en het implementeren van zijn DropInteraction
gedelegeerde methode:
laat dropInteraction = UIDropInteraction (delegate: dropInteractionDelegate) view.addInteraction (dropInteraction)
Om aan te geven of een weergave sleepitems kan accepteren of weigeren, implementeren we de dropInteraction (_: canHandle :)
protocol methode. De volgende methode laat ons beeld het systeem vertellen of het de items kan accepteren, door het type objecten te vermelden dat het kan ontvangen - in dit geval UIImages.
func dropInteraction (_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool // Expliciet vermeld het type acceptabele drop-item hier return session.canLoadObjects (ofClass: UIImage.self)
Als het view-object geen drop-interacties accepteert, moet u false van deze methode retourneren.
Bind vervolgens een dropvoorstel om gegevens uit de drop-sessie te accepteren. Hoewel dit een optionele methode is, wordt het ten zeerste aanbevolen om deze methode te implementeren, omdat deze visuele aanwijzingen geeft of de drop het item zal kopiëren, verplaatsen of dat de drop volledig wordt geweigerd. Door de dropInteraction (_: sessionDidUpdate :)
protocolmethode, die a retourneert UIDropProposal
, u geeft het voorgestelde type aan met behulp van het specifieke type bewerkingstabel (UIDropOperation
). De geldige typen die u kunt retourneren zijn:
annuleren
verboden
kopiëren
verhuizing
func dropInteraction (_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal // Signaal aan het systeem dat u het item van de bronapp verplaatst (u zou ook .copy kunnen aangeven om te kopiëren in plaats van te verplaatsen) return UIDropProposal ( bewerking: .move)
En tot slot, om de gegevensiteminhoud binnen uw bestemmingslocatie te consumeren, implementeert u de dropInteraction (_: performDrop :)
protocolmethode in de achtergrondwachtrij (in plaats van in de hoofdwachtrij - dit zorgt voor reactievermogen). Dit wordt hieronder geïllustreerd:
func dropInteraction (_ interaction: UIDropInteraction, performDrop session: UIDropSession) // Consume UIImage drag items session.loadObjects (ofClass: UIImage.self) items in let images = items as! [UIImage] self.imageView.image = images.first
We hebben aangetoond hoe u slepen en neerzetten in een aangepaste weergave zou implementeren, dus laten we nu naar het praktische deel van deze zelfstudie gaan en slepen en neerzetten implementeren in een app met een tabelweergave.
Tot dusverre hebben we besproken hoe we slepen en neerzetten in aangepaste weergaven kunnen implementeren, maar Apple heeft het ook gemakkelijk gemaakt om tabelweergaven en verzamelweergaven met slepen en neerzetten te vergroten. Terwijl tekstvelden en weergaven automatisch slepen en neerzetten ondersteunen, geven tabel- en verzamelweergaven specifieke methoden, gedelegeerden en eigenschappen voor het aanpassen van hun drag-en-drop-gedrag. We zullen dit binnenkort bekijken.
Begin met het maken van een nieuw project in Xcode 9, zodat u zeker weet dat u selecteert Master-Detail App vanuit het sjabloonvenster:
Voordat je aan de rest van de stappen gaat werken, ga je gang en bouw en ren je het project uit en speel je er een beetje mee. Je zult zien dat het een nieuwe tijdstempeldatum genereert wanneer je de plus selecteert (+) knop. We gaan deze app verbeteren door de gebruiker toe te staan de tijdstempels te slepen en te bestellen.
Slepen en neerzetten wordt ondersteund in tabelweergaven (evenals collecties) via gespecialiseerde API's die het slepen en neerzetten met rijen mogelijk maken door onze tabelweergave aan te passen om zowel de UITableViewDragDelegate
en UITableViewDropDelegate
protocols. Open de MasterViewController.swift bestand en voeg het volgende toe aan de viewDidLoad ()
methode:
override func viewDidLoad () super.viewDidLoad () ... self.tableView.dragDelegate = self self.tableView.dropDelegate = self ...
Net als bij aangepaste weergaven moeten we de nieuwe sleepsessie afhandelen wanneer de gebruiker een geselecteerde rij of meerdere rijen / selecties sleept. We doen dit met de gedelegeerde methode tableView (_: itemsForBeginning: bij :)
. Binnen deze methode retourneert u een bevolkte array die het slepen van de geselecteerde rijen begint, of een lege array om te voorkomen dat de gebruiker inhoud van dat specifieke indexpad sleept.
Voeg de volgende methode toe aan uw MasterViewController.swift het dossier:
func tableView (_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] let dateItem = self.objects [indexPath.row] as! String let data = dateItem.data (using: .utf8) laat itemProvider = NSItemProvider () itemProvider.registerDataRepresentation (forTypeIdentifier: kUTTypePlainText as String, visibility: .all) invullen voltooid (data, nul) return nihil return [UIDragItem ( itemProvider: itemProvider)]
Een deel van de toegevoegde code hoort u al bekend te zijn uit de vorige sectie, maar in wezen is het maken van een gegevensitem uit het geselecteerde object, wikkel het in een NSItemProvider
, en stuur het terug in a DragItem
.
Als u onze aandacht richt op het inschakelen van de drop-sessie, gaat u verder met het toevoegen van de volgende twee methoden:
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 (bewerking: .move, intent: .insertAtDinationLdeDropPath) else return UITableViewDropProposal (bewerking:. kopie, intentie: .insertAtDinationLinedPath)
De eerste methode vertelt het systeem dat het String-gegevenstypen kan verwerken als onderdeel van de drop-sessie. De tweede gedelegeerde methode, tableView (_: dropSessionDidUpdate: withDestinationIndexPath :)
, traceert de mogelijke droplocatie en meldt de methode bij elke wijziging. Het geeft ook visuele feedback weer om de gebruiker te laten weten of een specifieke locatie verboden of aanvaardbaar is, met behulp van een kleine visuele icoonkeu.
Ten slotte verwerken we de drop en consumeren we het data-item, bellen tableView (_: performDropWith :)
, ophalen van de rij met het versleepte gegevensitem, bijwerken van de gegevensbron van onze tabelweergave en invoegen van de benodigde rijen in de tabel.
func tableView (_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) let destinationIndexPath: IndexPath if let indexPath = coordinator.destinationIndexPath destinationIndexPath = indexPath else // Krijg laatste indexpad van tabelweergave. let section = tableView.numberOfSections - 1 let row = tableView.numberOfRows (inSection: sectie) destinationIndexPath = IndexPath (rij: rij, sectie: sectie) coordinator.session.loadObjects (ofClass: NSString.self) items in // Consume items verslepen. laat stringItems = items zoals! [String] var indexPaths = [IndexPath] () voor (index, item) in stringItems.enumerated () let indexPath = IndexPath (rij: destinationIndexPath.row + index, sectie: destinationIndexPath.section) self.objects.insert (item , at: indexPath.row) indexPaths.append (indexPath) tableView.insertRows (at: indexPaths, with: .automatic)
Voor meer informatie over het ondersteunen van slepen en neerzetten in uw tabelweergaven, raadpleegt u de eigen ontwikkelaarsdocumentatie over het ondersteunen van slepen en neerzetten in tabelweergaven.
Met de inhoud die we hebben behandeld, kunt u slepen en neerzetten implementeren in uw apps, zodat gebruikers visueel en interactief inhoud kunnen verplaatsen binnen hun bestaande apps, evenals in apps.
Naast de technische kennis van het implementeren van slepen en neerzetten, is het echter absoluut noodzakelijk dat u de tijd neemt om na te denken over hoe u slepen en neerzetten kunt implementeren, volgens de best practices die Apple voorschrijft in hun Human Interface Guidelines (HIG), in om gebruikers de best mogelijke iOS 11-gebruikerservaring te bieden.
Om het af te ronden, zullen we enkele van de belangrijkste aspecten bespreken, te beginnen met visuele aanwijzingen. Volgens de HIG is de fundamentele ervaring met slepen en neerzetten dat wanneer een gebruiker interactie heeft met bepaalde inhoud, visuele aanwijzingen voor de gebruiker een actieve sleepsessie aangeven, aangeduid door het laten stijgen van het inhoudselement, samen met een badge om aan te geven wanneer dropping is of is niet mogelijk.
We hebben deze best practice reeds in onze eerdere voorbeelden gebruikt, toen we de tableView (_: dropSessionDidUpdate: withDestinationIndexPath :)
methode, waarbij wordt aangegeven of de doelbestemming een verplaatsing, een kopie of een verbod is. U moet ervoor zorgen dat u met de aangepaste weergaven en interacties de verwachte set gedrag behoudt die andere iOS 11-apps, met name systeem-apps, ondersteunen.
Een ander belangrijk aspect om te overwegen, is beslissen of uw sleepsessie zal leiden tot een zet of kopie. Als algemene vuistregel stelt Apple dat wanneer je in dezelfde app werkt, dit over het algemeen moet resulteren in een zet, terwijl het logischer is om het gegevensitem te kopiëren wanneer je tussen verschillende apps sleept. Hoewel er uitzonderingen zijn, is het onderliggende principe natuurlijk dat het logisch is voor de gebruiker en wat ze verwachten dat zou moeten gebeuren.
Je moet ook denken in termen van bronnen en bestemmingen, en of het zinvol is om iets te slepen of niet.
Laten we eens kijken naar enkele van de eigen systeemhulpprogramma's van Apple. Met opmerkingen kunt u bijvoorbeeld tekstcontent selecteren en verslepen naar andere locaties in de app of naar andere apps op de iPad via gesplitst scherm. Met de app Herinneringen kunt u herinneringsitems verplaatsen van de ene naar de andere lijst. Denk in termen van functionaliteit na over hoe gebruikers uw inhoud gebruiken.
De leidraad van Apple is dat alle inhoud die bewerkbaar is, ondersteuning zou moeten bieden voor het accepteren van inhoud die is laten vallen, en elke inhoud die selecteerbaar is, moet versleepbare inhoud accepteren, naast het ondersteunen van kopiëren en plakken voor dat type elementen. Door gebruik te maken van standaard systeemtekstweergaven en tekstvelden, krijgt u ondersteuning voor slepen en neerzetten uit de doos.
U moet ook ondersteuning bieden voor slepen en neerzetten met meerdere items, in plaats van alleen losse items te ondersteunen, waarbij gebruikers met meer dan één vinger tegelijkertijd meerdere items kunnen selecteren, waarbij de geselecteerde items in een groep worden gestapeld om naar hun beoogde bestemmingen te worden verzonden. Een voorbeeld hiervan is het selecteren van meerdere afbeeldingen in de app Foto's of meerdere bestanden in de app Bestanden.
Een laatste richtlijn is om gebruikers de mogelijkheid te bieden een actie ongedaan te maken of een dropdown te "ongedaan maken". Gebruikers zijn al heel lang gewend aan het concept van het ongedaan maken van een actie in de meeste van de populaire apps, en slepen en neerzetten zou geen uitzondering moeten zijn. Gebruikers moeten het vertrouwen hebben om een sleepopdracht te kunnen starten en in staat te zijn om die actie ongedaan te maken als ze het element op de verkeerde bestemming neerzetten.
Er zijn veel meer praktische richtlijnen voor slepen en neerzetten dan waar we naar hebben gekeken, waaronder hoe u visuele aanwijzingen kunt onderdrukken, mislukte afgebroken acties kunt weergeven en voortgangsindicatoren voor niet-directe sleepsessies, zoals gegevensoverdrachten. Raadpleeg de Apple Human Interface Guidelines van Apple over slepen en neerzetten voor de volledige lijst met best practices.
In deze zelfstudie heb je geleerd hoe je je iOS-apps kunt verrijken met slepen en neerzetten, met dank aan iOS 11. Gaandeweg hebben we onderzocht hoe aangepaste weergaven en tabelweergaven kunnen worden ingeschakeld als sleepbronnen en bestemmingslocaties.
Als onderdeel van de iOS-evolutie naar een meer gebarengestuurde gebruikersinterface, zal ongetwijfeld slepen en neerzetten voor gebruikers in het hele systeem snel een verwachte functie worden, en als zodanig moeten alle apps van derden ook conform zijn. En net zo belangrijk als het implementeren van slepen en neerzetten, moet u het goed implementeren, zodat het een tweede natuur is voor gebruikers, inclusief eenvoud en functionaliteit.
En terwijl je hier bent, bekijk enkele van onze andere berichten over de ontwikkeling van iOS-apps!