Vor einigen Wochen fand im Yandex-Büro eine Sonderveranstaltung der CocoaHeads-Community statt - größer als herkömmliche Mitaps. Entwickler Anton Sergeev sprach bei diesem Treffen über das Mikrointeraktionsmodell, das UX-Designer normalerweise verwenden, sowie darüber, wie die darin enthaltenen Ideen in die Praxis umgesetzt werden können. Anton achtete am meisten auf Animation.
- Es ist mir sehr wichtig, dass es mir eine Ehre war, die Gäste zu treffen. Ich sehe hier diejenigen, mit denen ich schon sehr lange zusammen bin, mit denen ich kürzlich zusammen war und mit denen ich mich noch nicht getroffen habe. Willkommen bei CocoaHeads.
Ich erzähle Ihnen von Mikrointeraktionen. Dies ist ein kleiner Clickbait - wir sind Ingenieure, Entwickler, wir werden mehr über den Softwareteil sprechen, aber beginnen wir mit einem sehr humanitären Thema wie Mikrointeraktionen. Infolgedessen werden wir dieses humanitäre Thema im technischen Teil anwenden, um zu lernen, wie sehr kleine visuelle Komponenten wie Knöpfe, kleine Lader und Balken effizienter und einfacher gestaltet werden können. Sie sind mit Animationen gesättigt, und verzweigter Animationscode kann oft sehr kompliziert aussehen. Die Wartung ist äußerst schwierig.
Aber zuerst ein wenig Ablenkung. Denken Sie darüber nach, erinnern Sie sich, als Sie beschlossen, Entwickler zu werden? Ich erinnere mich deutlich daran. Alles begann mit einem Tisch. Einmal habe ich beschlossen, ObjC zu lernen. Modische Sprache, Spaß, einfach so, ohne weitreichende Pläne. Ich fand anscheinend ein Buch, Big Nerd Ranch, und fing an, Kapitel für Kapitel zu lesen, jede Übung zu machen, zu überprüfen, zu lesen, bis ich den Tisch erreichte. Dann habe ich mich zuerst mit dem Delegatenmuster vertraut gemacht, genauer mit seiner Unterart „Datenquelle“, Datenquelle. Dieses Paradigma erscheint mir jetzt sehr einfach: Es gibt eine Datenquelle, Delegierter, alles ist einfach. Aber dann hat es mich umgehauen: Wie kann ich eine Tabelle von völlig anderen Daten trennen? Sie haben einmal eine Tabelle auf einem Blatt Papier gesehen, in die Sie unendlich viele Zeilen und vollständig abstrakte Daten einfügen können. Es hat mich sehr beeinflusst. Ich erkannte, dass Programmierung und Entwicklung enorme Möglichkeiten bieten und es sehr interessant sein wird, sie anzuwenden. Seitdem habe ich mich entschieden, Entwickler zu werden.
Während der Entwicklung wurden verschiedene Muster angetroffen. Riesige, sogenannte Architekturen, die die gesamte Anwendung beschreiben. Kleine, die in Dutzende auf Knopfdruck passen. Es ist wichtig zu verstehen, dass all diese Muster nicht aus der Luft stammen, sondern aus dem humanitären Bereich. Das gleiche Delegatenmuster. Die Delegation erschien lange vor der Programmierung, und die Programmierung übernimmt all diese humanitären Dinge für eine effizientere Arbeit.
Heute werde ich über einen anderen Ansatz sprechen, der eine andere humanitäre Sache übernimmt. Insbesondere über Mikrointeraktionen.
Alles begann mit einem Lader. Bei der vorherigen Arbeit vor Yandex hatte ich die Aufgabe, den Google Material Design Loader zu wiederholen. Es gibt zwei davon, eine unbestimmte, eine andere definierte. Ich hatte die Aufgabe, sie zu einer zu kombinieren, er musste sowohl sicher als auch unbestimmt sein können, aber es gab strenge Anforderungen - damit es extrem reibungslos lief. Wir können jederzeit von einem Zustand in einen anderen wechseln, und alles sollte reibungslos und genau animiert sein.
Ich bin ein kluger Entwickler, ich habe alles getan. Ich habe mehr als 1000 Zeilen unverständlichen Nudelcodes erhalten. Es hat funktioniert, aber ich erhielt einen coolen Kommentar zur Codeüberprüfung: "Ich hoffe wirklich, dass niemand diesen Code jemals bearbeiten wird." Und für mich ist es praktisch ungeeignet. Ich habe schrecklichen Code geschrieben. Es hat cool funktioniert, es war eine meiner besten Animationen, aber der Code war schrecklich.
Heute werde ich versuchen, den Ansatz zu beschreiben, den ich gefunden habe, nachdem ich diesen Job verlassen habe.

Beginnen wir mit dem humanitärsten Thema - Mikrointeraktionsmodellen. Wie sind sie eingebettet und wo sind sie im Allgemeinen in unseren Anwendungen versteckt? Lassen Sie uns dieses Modell in unserer technischen Welt weiter verwenden. Überlegen Sie, wie UIView, das sich mit Anzeige und Animation befasst, wie dies funktioniert. Insbesondere werden wir viel über den CAAction-Mechanismus sprechen, der eng in UIView, CALayer, integriert ist und mit diesem zusammenarbeitet. Und dann betrachten Sie kleine Beispiele.
Definition zuerst. Anscheinend hat der Autor das Präfix "Mikro" wirklich gemocht, aber es gibt keine Makro- oder Nano-Wechselwirkungen, die Größe spielt keine Rolle. Der Einfachheit halber werden wir sie einfach Interaktionen nennen. Dies ist ein so praktisches Modell, mit dem Sie jede Interaktion mit der Anwendung von Anfang bis Ende beschreiben können. Es besteht aus vier Punkten: einem Auslöser, einer Geschäftslogik, die in dieser Interaktion implementiert werden muss, einem Feedback, um dem Benutzer etwas zu vermitteln, und einer Änderung des Anwendungsstatus.
Ich werde eine Geschichte mit drei verschiedenen Rollen erzählen. Ich werde mit dem Benutzer beginnen, als das Wichtigste in der Entwicklung. Als ich mich auf den Bericht vorbereitete, wurde ich krank. Ich musste eine Apotheke finden und öffnete Yandex.Map. Ich habe die Anwendung geöffnet, sieh sie dir an, sie sieht mich an, aber es passiert nichts. Dann wurde mir klar, dass ich der Benutzer bin, ich bin der Hauptbenutzer. Ich gebe Anweisungen, was für die Anwendung zu tun ist. Ich orientierte mich, klickte auf die Schaltfläche "Suchen", gab "Apotheke" ein, klickte auf "OK", die Anwendung erledigte die interne Arbeit, fand die erforderlichen Apotheken neben mir und zeigte sie auf dem Bildschirm an.
Ich suchte nach der richtigen und stellte fest, dass zusätzlich zu den Apotheken eine spezielle Schaltfläche auf dem Bildschirm angezeigt wurde - um eine Route zu erstellen. Somit ist die Anwendung in einen neuen Zustand versetzt worden. Ich klickte darauf und ging in die Apotheke. Ich bin aus irgendeinem Grund in diese Anwendung gegangen - um eine Apotheke zu finden. Ich habe sie erreicht. Ich bin ein glücklicher Benutzer.
Bevor diese Anwendung erschien und ich nach etwas darin suchen konnte, wurde sie zuerst entwickelt. Was dachte der UX-Designer, als er diesen Prozess entwickelte? Alles begann mit der Tatsache, dass es notwendig war, aus einer Stummschaltungsszene herauszukommen, wenn sich Benutzer und Anwendung gegenseitig ansehen und nichts passiert. Dafür wurde eine Art Auslöser benötigt. Alles hat einen Anfang, und auch hier musste man irgendwo anfangen.
Der Auslöser wurde ausgewählt - Suchtaste. Beim Klicken war es notwendig, das Problem aus technischer Sicht zu lösen. Daten auf dem Server anfordern, Antwort analysieren, Modell irgendwie aktualisieren, analysieren. Fordern Sie die aktuelle Position der Benutzer und mehr an. Wir haben diese Daten erhalten und wissen genau, wo sich alle Apotheken befinden.
Es scheint möglich zu sein, dies zu beenden. Immerhin haben wir das Problem gelöst, alle Apotheken gefunden. Es gibt nur ein Problem: Der Benutzer weiß immer noch nichts über diese Apotheken. Er muss es vermitteln.
Irgendwie packen wir unsere Lösung für dieses Problem und bringen sie ihm in einem schönen Paket, damit er es versteht. Es ist so passiert, dass Benutzer Menschen sind, sie interagieren mit der Außenwelt über die Sinne. Der aktuelle Stand der Technik ist so, dass wir als Entwickler mobiler Anwendungen nur drei Sinne haben: Sehen - wir können etwas auf dem Bildschirm zeigen, Hören - wir können es in den Lautsprechern reproduzieren und ein taktiles Gefühl können wir den Benutzer in die Hand drücken.
Aber der Mensch ist viel funktionaler. Der aktuelle Stand der Technik ist jedoch so, dass wir uns derzeit nur auf diese drei verlassen können. In diesem Fall wählen wir einen Bildschirm aus, zeigen auf der Karte die nächstgelegenen Apotheken und eine Liste mit detaillierteren Informationen zu diesen Apotheken. Und es scheint, dass dies genau alles ist, der Benutzer Apotheken gefunden hat und alles in Ordnung ist.
Aber es gibt ein Problem. Als der Benutzer die Anwendung eingab, befand er sich in einem Kontext, in dem er nicht wusste, wo sich die Apotheken befanden. Und seine Aufgabe war es, sie zu finden. Aber jetzt hat sich der Kontext geändert, er weiß, wo die Apotheken sind, er muss nicht mehr nach ihnen suchen. Er hatte die folgende Aufgabe - Wegbeschreibungen zur nächsten Apotheke zu bekommen. Aus diesem Grund müssen zusätzliche Steuerelemente auf dem Bildschirm angezeigt werden. Dies ist insbesondere eine Schaltfläche zum Erstellen einer Route, dh zum Übertragen der Anwendung in einen anderen Status, in dem sie bereit ist, neue Trigger für die nächsten Interaktionen wieder zu akzeptieren.
Stellen Sie sich vor, der UX-Designer hat sich all das ausgedacht, kommt zum Entwickler und beginnt in Farben zu beschreiben, wie der Benutzer auf die Schaltfläche klickt, wie und was passiert, wie gesucht wird, wie der Benutzer zufrieden ist, wie wir die DAU erhöhen und so weiter. Der Stapel ungelöster Fragen des Entwicklers lief im ersten Satz an einer anderen Stelle über, als wir den Button zum ersten Mal erwähnten.
Er hört geduldig auf alles und am Ende, wenn es endet, sagt er, dass das cool ist, aber lassen Sie uns den Knopf besprechen. Dies ist ein wichtiges Element.
Während der Diskussion stellt sich heraus, dass die Schaltfläche von Natur aus ein Auslöser ist, sie enthält Logik in sich, nach der sie Nachrichten vom System empfangen kann, insbesondere über Benutzerklicks auf den Bildschirm. Basierend auf diesem Klick kann eine Ereigniskette gestartet werden, die mit der Tatsache beginnt, dass dieselbe Schaltfläche Nachrichten an verschiedene Objekte sendet, in denen die Notwendigkeit zum Starten verschiedener Prozesse angegeben wird. In diesem Fall werden Informationen auf dem Server angefordert.
Wenn die Taste gedrückt wird, ändert sie ihren Status und wird gedrückt. Wenn der Benutzer loslässt, wird er nicht mehr gedrückt. Das heißt, es gibt dem Benutzer Feedback, damit er versteht, was von dieser Schaltfläche zu erwarten ist. Und die Taste kann in verschiedenen Zuständen gedrückt, nicht gedrückt, aktiv oder inaktiv sein und sich nach unterschiedlicher Logik von einem Zustand in einen anderen bewegen.
So haben wir gesehen, dass dasselbe Mikrointeraktionsmodell, das aus einem Auslöser, einer Geschäftslogik, Rückmeldungen und Statusänderungen besteht, unsere Anwendung auf verschiedenen Skalen beschreiben kann, wie auf der Skala eines gesamten Benutzerfalls, einer riesigen Suche nach der nächsten Apotheke. also in Bezug auf einen kleinen Knopf.
Und dies ist ein sehr praktisches Modell, mit dem Sie die Interaktion innerhalb des Teams vereinfachen und programmgesteuert vier Entitäten trennen können: Trigger, Geschäftslogik, Feedback und Statusänderung. Mal sehen, was uns UIKit bietet, um es zu nutzen. Und bietet nicht nur, sondern nutzt. Bei der Implementierung verschiedener Animationen, der kleinen Komponenten der UIView-Unterklassen, wird nur dieser Mechanismus verwendet und nicht anders.
Beginnen wir mit UIView, wie es in dieses Modell passt. Dann werden wir CALayer betrachten, das es uns bietet, um diese Staaten zu unterstützen, und wir werden den Wirkungsmechanismus als den interessantesten Moment betrachten.
Beginnen wir mit dem UIView. Wir verwenden es, um einige Rechtecke auf dem Bildschirm anzuzeigen. Tatsächlich weiß UIView jedoch nicht, wie es sich selbst zeichnen soll, sondern verwendet dafür ein anderes CALayer-Objekt. Tatsächlich ist UIView verpflichtet, Nachrichten über das Berühren des Systems sowie über andere Aufrufe der API zu empfangen, die wir in unseren Unterklassen von UIView definiert haben. Somit implementiert UIView selbst die Triggerlogik, dh den Start einiger Prozesse, die diese Nachrichten vom System empfangen.
UIView kann seine Delegierten auch über aufgetretene Ereignisse benachrichtigen und Nachrichten an Abonnenten senden, um beispielsweise UIControl-Unterklassen zu unterschiedlichen Ereignissen zu machen. Auf diese Weise wird die Geschäftslogik dieses UIView implementiert. Nicht alle von ihnen haben Geschäftslogik, viele von ihnen sind nur Anzeigeelemente und haben kein Feedback im Sinne von Geschäftslogik.

Wir haben uns zwei Punkte angesehen, einen Auslöser und eine Geschäftslogik. Und wo sind Feedback und Statusänderungen in UIView verborgen? Um dies zu verstehen, müssen wir uns daran erinnern, dass UIView nicht für sich existiert. Beim Erstellen wird eine Hintergrundschicht erstellt, eine Unterklasse von CALayer.

Und ernennt sich zu seinem Delegierten. Um zu verstehen, wie UIView CALayer verwendet, kann es in verschiedenen Zuständen existieren.
Wie kann man einen Staat von einem anderen unterscheiden? Sie unterscheiden sich in der Menge der Daten, die irgendwo gespeichert werden müssen. Wir werden prüfen, welche Funktionen CALayer für UIView bereitstellt, damit der Status gespeichert wird.

Unsere Oberfläche wird etwas erweitert, die Interaktion zwischen UIView und CALayer, UIView hat eine zusätzliche Aufgabe - das Repository in CALayer zu aktualisieren.
Eine wenig bekannte Tatsache, die nur wenige Leute verwenden: CALayer kann sich wie ein assoziatives Array verhalten, was bedeutet, dass wir beliebige Daten auf jeden Schlüssel wie folgt schreiben können: setValue (_: forKey :).

Diese Methode ist in allen NSObject-Unterklassen vorhanden, stürzt jedoch im Gegensatz zu vielen anderen nicht ab, wenn ein Schlüssel empfangen wird, der nicht damit überschrieben wird. Und er schreibt es richtig auf, und dann können wir es lesen. Dies ist eine sehr praktische Sache, die es ermöglicht, ohne Unterklassen von CALayer zu erstellen, Daten dort zu schreiben und sie dann zu lesen und zu konsultieren. Aber dies ist ein sehr primitives einfaches Repository, in der Tat ein Wörterbuch. CALayer ist viel progressiver. Es unterstützt Stile.
Dies wird durch die Style-Eigenschaft implementiert, über die jeder CALayer verfügt. Standardmäßig ist es Null, aber wir können es neu definieren und verwenden.

Im Allgemeinen ist dies ein reguläres Wörterbuch und nichts weiter, aber es hat eine Besonderheit darüber, wie CALayer damit arbeitet, wenn wir nach dem Wert für Key fragen, einer anderen Methode, die NSObject hat. Es wirkt sehr interessant, es sucht rekursiv nach den notwendigen Werten im Stilwörterbuch. Wenn wir einen vorhandenen Stil mit dem Stilschlüssel in einen neuen Stil packen und dort einige Schlüssel schreiben, sieht dies jedoch folgendermaßen aus.

Schauen Sie sich zuerst die Wurzel an, dann das Landesinnere und so weiter, bis es Sinn macht. Wenn Stil gleich Null wird, macht es keinen Sinn, weiter zu schauen.
Auf diese Weise kann UIView mithilfe der von CALayer bereitgestellten Infrastruktur Statusänderungen organisieren, das interne CALayer-Repository aktualisieren, entweder mithilfe von style, einem sehr leistungsstarken Repository, das einen Stapel simulieren kann, oder mithilfe eines regulären assoziativen Arrays, das ebenfalls sehr effizient und sehr nützlich ist .
Beginnen Sie mit der Speicherung und beginnen Sie mit CAAction. Ich werde dir mehr über ihn erzählen.

Es gibt eine neue Aufgabe für UIView - Aktionen von CALayer anzufordern. Was sind Aktionen?

CAAction ist nur ein Protokoll, für das nur eine Methode ausgeführt wird. Apple liebt im Allgemeinen Kinothemen, Action hier als "Kamera, Motor!". Dieser „Motor“ ist nur eine Aktion, und nicht nur dieser Name wurde verwendet. Die Ausführungsmethode bedeutet, dass eine Aktion gestartet wird, die gestartet, ausgeführt und beendet werden kann. Dies ist die wichtigste. Diese Methode ist sehr allgemein gehalten, hat nur eine Ereigniszeichenfolge und alles andere kann von einem beliebigen Typ sein. In ObjC ist dies alles ID und ein normales NSDictionary.

Es gibt Klassen in UIKit, die das CAAction-Protokoll erfüllen. Das erste ist Animation. Erstens wissen wir, dass Animation zu einer Ebene hinzugefügt werden kann, aber dies ist eine sehr einfache Sache. Eine übergeordnete Abstraktion darüber besteht darin, eine Aktion mit den erforderlichen Parametern mit einer Ebene auszuführen.
Die zweite wichtige Ausnahme ist NSNull. Wir wissen, dass er mit keiner Methode aufgerufen werden kann, aber er erfüllt das CAAction-Protokoll, und dies geschieht, um bequem in Schichten nach CAAction zu suchen.

Wie bereits erwähnt, ist UIView ein Delegat an CALayer, und eine der Delegatenmethoden ist action (für: forKey :). Die Ebene hat eine Methode, Aktion für Schlüssel.

Wir können es jederzeit auf der Ebene aufrufen, und es wird jederzeit die richtige Aktion oder Null geben, da es auch geben kann. Der Algorithmus ist eine sehr ungewöhnliche Suche. Der Pseudocode ist hier geschrieben, schauen wir uns die Zeilen an. Nach Erhalt einer solchen Nachricht konsultiert er zunächst den Delegierten. Ein Delegat kann entweder null zurückgeben, was bedeutet, dass die Suche an anderer Stelle fortgesetzt werden soll, oder er kann eine gültige Aktion zurückgeben, ein gültiges Objekt, das das CAAction-Protokoll erfüllt. Es gibt jedoch eine logische Regel: Wenn NSNull zurückgegeben wird, das dieses Protokoll erfüllt, wird es später in nil konvertiert. Das heißt, wenn wir Null zurückgeben, bedeutet dies tatsächlich "Suche beenden". Es gibt keine Aktion und es ist nicht notwendig.
Aber es gibt folgendes. Nachdem er sich mit dem Delegierten beraten hatte und der Delegierte gleich Null zurückgekehrt war, suchte er weiter. Zuerst im Aktionswörterbuch, über das die Ebene verfügt, und dann wird rekursiv im Stilwörterbuch gesucht, wo es auch ein Wörterbuch mit dem Aktionsschlüssel geben kann, in das viele Aktionen geschrieben werden können, und es kann auch rekursiv nach ihnen suchen. Wenn es dort nicht geklappt hat, fragt er die Klasse nach der Standardaktion für die Key-Methode, die von CALayer definiert wird und bis vor kurzem etwas zurückgegeben hat. In den letzten Versionen von iOS wird jedoch in letzter Zeit immer Null zurückgegeben.
Verstand die Theorie. Mal sehen, wie alles in der Praxis angewendet wird.
Es gibt Ereignisse, sie haben Schlüssel, einige Aktionen finden für diese Ereignisse statt. Grundsätzlich können zwei verschiedene Arten von Ereignissen unterschieden werden. Das erste ist die Animation gespeicherter Eigenschaften. Angenommen, wenn wir Viewcolor = red in View aufrufen, ist es theoretisch möglich, zu animieren.

Welcher Bericht über Muster ohne Schaltung? Ich habe ein paar gezeichnet. UIView verfügt über eine Art Schnittstelle, die wir für Unterklassen definiert haben oder die vom System mit Ereignissen empfangen wird. Die Aufgabe von UIView besteht darin, die gewünschte Aktion anzufordern, den internen Speicher zu aktualisieren und die aufgetretene Aktion zu starten. Die Reihenfolge ist in Bezug auf die Anforderung sehr wichtig: Aktion, nur dann die Aktion aktualisieren und erst dann den Speicher und die Aktion aktualisieren.

Was passiert, wenn wir bei UIView backgroundColor aktualisieren? Wir wissen, dass in UIView alles, was mit der Anzeige auf dem Bildschirm zu tun hat, immer noch ein Proxy für CALayer ist. Er speichert alles, was er erhält, für alle Fälle zwischen, aber gleichzeitig sendet alles CALayer, und er befasst sich weiter mit der gesamten Logik von CALayer. CALayer, ? .

. , . CALayer , backgroundColor, store, run, CALayer . , , , .
UIView, backgroundColor UIView, , , , .

, . , UIView CALayer, . Alles ist sehr einfach.
, - . , NSNull, , . , CALayer .
, UIView , . . ?

, . UIView , read only, , inheritedAnimationDuration. . , . .
? duration, . , run, , .

, CAAction, backgroundcolor opacity, UIView . , , , , . . setValue forKey , , , , , , .
, , , , .
— . , «» «» . .
.

. , , , . UIView CALayer, , , CAAction, , , .


, , , . , . .
. - .
CAAction, , . , , , .

, , , home, . , . , .

. - .

, - , - . , , . , .
, , .

, CAAction , . , UIControl, - , - , , , - .
, . , UIView -, , - , , , .
— . .
? . , . — . activating, inactive active. , , .

. , onOrderIn onOrderOut. , UIKit, .
, -, — , .

. UIView , : isActive progress. . CAAction, .
, . , , 30 CAACtion, . , 30 , NSNull. 15 15 . . — . , — .
, . .
. , , : , -, .
Indem wir alle Wechselwirkungen in diese vier Teile zerlegen, können wir die Logik des einen mit dem anderen nicht stören, vereinfachen. Versuchen Sie daher, Ihre Anwendungen und verschiedene Aufgaben mithilfe dieser Mikrointeraktionen zu analysieren. Denken Sie daran, dass UIKit eine riesige Infrastruktur bietet, um dies bequem und schön zu tun. Vernachlässige sie nicht. Oft gibt es sehr alte Methoden, sie werden selten verwendet, aber sie sind sehr wichtig und helfen Ihnen, Ihre Elemente schön, einfach und schnell zu realisieren. Vielen Dank für Ihre Aufmerksamkeit.