Beberapa minggu yang lalu, sebuah acara khusus komunitas CocoaHeads diadakan di kantor Yandex - lebih besar dari mitaps tradisional. Pengembang Anton Sergeyev berbicara pada pertemuan ini dan berbicara tentang model interaksi mikro yang biasanya digunakan desainer UX, serta bagaimana menerapkan ide-ide di dalamnya. Anton sangat memperhatikan animasi.
- Sangat penting bagi saya bahwa itu adalah kehormatan saya untuk bertemu para tamu. Saya melihat di sini orang-orang yang sudah lama saya kenal, orang-orang yang baru-baru ini saya kenal, dan orang-orang yang belum saya kenal. Selamat datang di CocoaHeads.
Saya akan memberi tahu Anda tentang interaksi mikro. Ini sedikit clickbait - kami adalah insinyur, pengembang, kami akan berbicara lebih banyak tentang bagian perangkat lunak, tetapi kami akan mulai dengan topik yang sangat kemanusiaan, seperti interaksi mikro. Sebagai hasilnya, kami akan menerapkan tema kemanusiaan ini di bagian teknis untuk mempelajari cara mendesain komponen visual yang sangat kecil dengan lebih efisien, seperti tombol, loader kecil, balok. Mereka dipenuhi dengan animasi, dan kode animasi bercabang sering terlihat sangat rumit, sangat sulit untuk dipertahankan.
Tapi pertama-tama, sedikit gangguan. Pikirkan tentang hal ini, apakah Anda ingat ketika Anda memutuskan untuk menjadi pengembang? Saya ingat dengan jelas itu. Semuanya dimulai dengan sebuah meja. Suatu kali saya memutuskan untuk belajar ObjC. Bahasa yang modis, menyenangkan, begitu saja, tanpa rencana yang luas. Saya menemukan sebuah buku, tampaknya, Big Nerd Ranch, dan mulai membaca bab demi bab, melakukan setiap latihan, memeriksa, membaca, sampai saya mencapai meja. Kemudian saya pertama kali berkenalan dengan pola delegasi, lebih tepatnya dengan subspesiesnya "Sumber data", sumber data. Paradigma ini tampaknya sangat sederhana bagi saya sekarang: ada sumber data, delegasikan, semuanya sederhana. Tapi kemudian itu terlintas di benak saya: bagaimana saya bisa memisahkan tabel dari data yang sama sekali berbeda? Anda pernah melihat meja di selembar kertas di mana Anda dapat menempatkan jumlah baris tak terbatas, data yang sepenuhnya abstrak. Itu sangat memengaruhi saya. Saya menyadari bahwa pemrograman, pengembangan memiliki peluang luar biasa, dan akan sangat menarik untuk menerapkannya. Sejak itu, saya memutuskan untuk menjadi pengembang.
Selama pengembangan, berbagai pola ditemui. Huge, yang disebut arsitektur yang menggambarkan keseluruhan aplikasi. Yang kecil masuk dalam lusinan tombol kecil. Penting untuk dipahami bahwa semua pola ini bukan berasal dari udara, tetapi dari sektor kemanusiaan. Pola delegasi yang sama. Delegasi muncul jauh sebelum pemrograman, dan pemrograman mengambil alih semua hal kemanusiaan ini untuk pekerjaan yang lebih efisien.
Hari ini saya akan berbicara tentang pendekatan lain yang mengambil alih hal kemanusiaan lainnya. Secara khusus, tentang interaksi mikro.
Semuanya dimulai dengan sebuah loader. Pada pekerjaan sebelumnya, sebelum Yandex, saya memiliki tugas untuk mengulang loader desain materi Google. Ada dua di antaranya, satu tidak pasti, yang lain didefinisikan. Saya memiliki tugas untuk menggabungkan mereka menjadi satu, ia harus dapat memastikan dan tidak terbatas, tetapi ada persyaratan yang ketat - sehingga sangat halus. Kapan saja, kita dapat berpindah dari satu kondisi ke kondisi lain, dan semuanya harus dianimasi dengan lancar dan akurat.
Saya adalah pengembang yang cerdas, saya melakukan segalanya. Saya mendapat lebih dari 1000 baris kode mie yang tidak dapat dipahami. Itu berhasil, tetapi saya menerima komentar keren pada ulasan kode: "Saya sangat berharap bahwa tidak ada yang akan mengedit kode ini." Dan bagi saya itu praktis tidak cocok. Saya menulis kode yang mengerikan. Itu bekerja dengan baik, itu adalah salah satu animasi terbaik saya, tetapi kode itu mengerikan.
Hari ini saya akan mencoba menggambarkan pendekatan yang saya temukan setelah saya meninggalkan pekerjaan itu.

Mari kita mulai dengan topik paling kemanusiaan - model interaksi mikro. Bagaimana mereka tertanam dan umumnya di mana mereka disembunyikan di aplikasi kita? Mari kita terus menggunakan model ini di dunia teknis kami. Pertimbangkan bagaimana UIView, yang berkaitan dengan tampilan dan animasi, cara kerjanya. Secara khusus, kami akan banyak berbicara tentang mekanisme CAAction, yang terintegrasi erat dengan dan bekerja dengan UIView, CALayer. Dan kemudian pertimbangkan contoh-contoh kecil.
Definisi dulu. Rupanya, penulis sangat menyukai awalan "mikro", tetapi tidak ada interaksi makro atau nano, ukurannya tidak masalah. Untuk kesederhanaan, kami menyebutnya interaksi semata. Ini adalah model yang nyaman yang memungkinkan Anda untuk menggambarkan interaksi apa pun dengan aplikasi, dari awal hingga selesai. Ini terdiri dari empat poin: pemicu, logika bisnis yang perlu diterapkan dalam interaksi ini, umpan balik untuk menyampaikan sesuatu kepada pengguna, dan perubahan dalam kondisi aplikasi.
Saya akan menceritakan satu kisah dengan tiga peran berbeda. Saya akan mulai dengan pengguna, sebagai hal terpenting dalam pengembangan. Ketika saya sedang bersiap untuk laporan itu, saya sakit. Saya perlu menemukan apotek, dan saya membuka Yandex.Map. Saya membuka aplikasi, lihat itu, itu menatap saya, tetapi tidak ada yang terjadi. Saya kemudian menyadari bahwa saya adalah pengguna, saya yang utama, saya memberikan instruksi tentang apa yang harus dilakukan untuk aplikasi. Saya mengarahkan, mengklik tombol "cari", masuk ke "apotek", mengklik "OK", aplikasi melakukan pekerjaan internal, menemukan apotek yang diperlukan di sebelah saya, dan menampilkannya di layar.
Saya mencari yang tepat dan menemukan bahwa selain apotek, tombol khusus muncul di layar - untuk membangun rute. Dengan demikian, aplikasi telah pindah ke keadaan baru. Saya mengkliknya, dan pergi ke apotek. Saya masuk ke aplikasi ini untuk beberapa alasan - untuk menemukan apotek. Saya mencapai dia. Saya adalah pengguna yang bahagia.
Sebelum aplikasi ini muncul, dan saya dapat mencari sesuatu di dalamnya, pertama kali dikembangkan. Apa yang dipikirkan oleh perancang UX ketika dia memulai proses ini? Semuanya dimulai dengan fakta bahwa perlu keluar dari adegan bisu ketika pengguna dan aplikasi saling memandang, dan tidak ada yang terjadi. Untuk ini, beberapa jenis pemicu diperlukan. Semuanya memiliki permulaan, dan di sini juga, itu perlu dimulai di suatu tempat.
Pemicu telah dipilih - tombol pencarian. Ketika mengkliknya, itu perlu untuk menyelesaikan masalah dari sudut pandang teknis. Minta data di server, parsing respons, entah bagaimana perbarui model, analisis. Minta posisi pengguna saat ini dan lainnya. Jadi kami mendapatkan data ini dan kami tahu persis di mana semua apotek berada.
Tampaknya mungkin untuk mengakhiri ini. Lagi pula, kami memecahkan masalah, menemukan semua apotek. Hanya ada satu masalah: pengguna masih tidak tahu apa-apa tentang apotek ini. Dia harus menyampaikannya.
Entah bagaimana caranya mengemas solusi kami untuk masalah ini dan membawanya ke dalam paket yang indah sehingga ia memahaminya. Kebetulan penggunanya adalah manusia, mereka berinteraksi dengan dunia luar melalui indra. Keadaan teknologi saat ini sedemikian rupa sehingga kita, sebagai pengembang aplikasi mobile, hanya memiliki tiga indera: penglihatan - kita dapat menunjukkan sesuatu di layar, mendengar - kita dapat mereproduksi di speaker, dan sensasi sentuhan, kita dapat mendorong pengguna di tangan.
Tetapi manusia jauh lebih fungsional. Tetapi keadaan teknologi saat ini sedemikian rupa sehingga saat ini kita hanya bisa mengandalkan ketiganya. Dan dalam hal ini kami memilih layar, menunjukkan pada peta apotek terdekat, dan dengan daftar dengan informasi lebih rinci tentang apotek ini. Dan tampaknya ini adalah segalanya, pengguna menemukan apotek dan semuanya baik-baik saja.
Tapi ada masalah. Ketika pengguna memasukkan aplikasi, ia berada dalam konteks di mana ia tidak tahu di mana apotek berada. Dan tugasnya adalah menemukannya. Tetapi sekarang konteksnya telah berubah, dia tahu di mana apotek berada, dia tidak perlu lagi mencarinya. Dia memiliki tugas berikut - untuk mendapatkan petunjuk ke apotek berikutnya. Itulah mengapa kita perlu menampilkan kontrol tambahan pada layar, khususnya, ini adalah tombol untuk membangun rute, yaitu, mentransfer aplikasi ke keadaan lain di mana ia siap untuk menerima pemicu baru untuk interaksi berikutnya lagi.
Bayangkan, desainer UX datang dengan semua ini, datang ke pengembang dan mulai menggambarkan dengan warna bagaimana pengguna mengklik tombol, bagaimana dan apa yang terjadi, bagaimana itu dicari, bagaimana pengguna bahagia, bagaimana kita meningkatkan DAU dan sebagainya. Tumpukan pertanyaan yang belum terselesaikan dari pengembang meluap ke tempat lain pada kalimat pertama, ketika kami pertama kali menyebutkan tombol.
Dia dengan sabar mendengarkan semuanya, dan pada akhirnya, ketika itu berakhir, dia mengatakan bahwa oke, ini keren, tapi mari kita bahas tombolnya. Ini adalah elemen penting.
Selama diskusi, ternyata tombol itu secara inheren merupakan pemicu, itu berisi logika di dalam dirinya, di mana ia dapat menerima pesan dari sistem, khususnya, tentang klik pengguna di layar. Berdasarkan klik ini, ia dapat memulai rangkaian peristiwa, yang dimulai dengan fakta bahwa tombol yang sama mengirim pesan ke objek yang berbeda tentang perlunya memulai berbagai proses, dalam hal ini, meminta informasi di server, beberapa lagi.
Saat ditekan, tombol berubah statusnya, menjadi ditekan. Ketika pengguna melepaskan, itu tidak lagi ditekan. Artinya, ini memberikan umpan balik kepada pengguna sehingga ia mengerti apa yang diharapkan dari tombol ini. Dan tombol dapat ditekan, tidak ditekan, aktif atau tidak aktif, dalam kondisi berbeda, dan bergerak sesuai dengan logika yang berbeda dari satu kondisi ke kondisi lainnya.
Dengan demikian, kami melihat bahwa model interaksi mikro yang sama, yang terdiri dari pemicu, logika bisnis, umpan balik, dan perubahan status, dapat menggambarkan aplikasi kami pada berbagai skala, seperti pada skala keseluruhan kasus pengguna, pencarian besar-besaran untuk apotek terdekat, jadi dalam hal tombol kecil.
Dan ini adalah model yang sangat nyaman yang memungkinkan Anda menyederhanakan interaksi dalam tim dan menjelaskan secara terprogram, memisahkan empat entitas: pemicu, logika bisnis, umpan balik, dan perubahan status. Mari kita lihat apa yang UIKit sediakan untuk kita gunakan. Dan tidak hanya menyediakan, tetapi menggunakan. Ketika menerapkan berbagai animasi, komponen kecil dari subkelas UIView, ia hanya menggunakan mekanisme ini, dan tidak berjalan dengan cara yang berbeda.
Mari kita mulai dengan UIView, bagaimana itu cocok dengan model ini. Kemudian kami akan mempertimbangkan CALayer yang disediakan untuk kami untuk mendukung negara-negara ini, dan kami akan mempertimbangkan mekanisme tindakan, momen yang paling menarik.
Mari kita mulai dengan UIView. Kami menggunakannya untuk menampilkan beberapa persegi panjang di layar. Tetapi pada kenyataannya, UIView tidak tahu cara menggambar dirinya sendiri, ia menggunakan objek CALayer lain untuk ini. Bahkan, UIView berkomitmen untuk menerima pesan tentang menyentuh sistem, serta tentang panggilan lain, tentang API yang kami definisikan dalam subkelas UIView kami. Dengan demikian, UIView sendiri mengimplementasikan logika pemicu, yaitu peluncuran beberapa proses, menerima pesan-pesan ini dari sistem.
UIView juga dapat memberi tahu delegasinya tentang peristiwa yang telah terjadi, dan juga mengirim pesan ke pelanggan, seperti, misalnya, membuat UIControl membuat subkelas acara yang berbeda. Dengan cara ini, logika bisnis UIView ini diimplementasikan. Tidak semua dari mereka memiliki logika bisnis, banyak dari mereka hanya elemen tampilan dan tidak memiliki umpan balik dalam arti logika bisnis.

Kami melihat dua poin, pemicu dan logika bisnis. Dan di mana umpan balik dan perubahan status disembunyikan di UIView? Untuk memahami ini, kita harus ingat bahwa UIView tidak ada dengan sendirinya. Saat dibuat, ia menciptakan backlayer, subkelas CALayer.

Dan menunjuk sendiri delegasinya. Untuk memahami bagaimana UIView menggunakan CALayer, itu bisa ada di berbagai negara.
Bagaimana membedakan satu negara dari yang lain? Mereka berbeda dalam set data yang perlu disimpan di suatu tempat. Kami akan mempertimbangkan fitur apa yang disediakan CALayer bagi kami untuk UIView, sehingga dapat menyimpan status.

Antarmuka kami sedikit melebar, interaksi antara UIView dan CALayer, UIView memiliki tugas tambahan - untuk memperbarui repositori di dalam CALayer.
Fakta yang sedikit diketahui yang digunakan oleh sedikit orang: CALayer dapat berperilaku sebagai array asosiatif, yang berarti bahwa kita dapat menulis data sewenang-wenang pada data tersebut dengan kunci apa saja sebagai berikut: setValue (_: forKey :).

Metode ini hadir di semua subclass NSObject, tetapi tidak seperti banyak subclass lainnya, ketika kunci diterima yang tidak diganti dengan itu, itu tidak crash. Dan dia menuliskannya dengan benar, lalu kita bisa membacanya. Ini adalah hal yang sangat nyaman, yang memungkinkan, tanpa membuat subclass dari CALayer, untuk menulis data apa pun di sana dan kemudian membacanya, berkonsultasi dengan mereka. Tapi ini adalah repositori sederhana yang sangat primitif, pada kenyataannya, satu kamus. CALayer jauh lebih progresif. Ini mendukung gaya.
Ini diterapkan oleh properti Style yang dimiliki CALayer mana pun. Secara default, ini nihil, tetapi kita dapat mendefinisikan ulang dan menggunakannya.

Secara umum, ini adalah kamus reguler dan tidak lebih, tetapi memiliki kekhasan tentang bagaimana CALayer bekerja dengannya, jika kita meminta nilai untuk Key, metode lain yang dimiliki NSObject. Kerjanya sangat menarik, mencari nilai-nilai yang diperlukan dalam kamus gaya secara rekursif. Jika kita mengemas satu gaya yang ada menjadi gaya baru dengan tombol gaya dan menulis beberapa tombol di sana, tetapi itu akan terlihat dengan cara berikut.

Pertama, lihat akarnya, lalu ke daratan dan seterusnya, sampai masuk akal. Ketika gaya menjadi nol, maka tidak masuk akal untuk melihat lebih jauh.
Dengan cara ini, UIView dapat, menggunakan infrastruktur yang disediakan CALayer, mengatur perubahan status, memperbarui repositori CALayer internal, baik menggunakan style, repositori yang sangat kuat yang dapat mensimulasikan tumpukan, atau menggunakan array asosiatif biasa, yang juga sangat efisien dan sangat berguna .
Selesai dengan penyimpanan, mulai dengan CAAction. Saya akan bercerita lebih banyak tentang dia.

Ada tugas baru bagi UIView - untuk meminta tindakan dari CALayer. Apa itu tindakan?

CAAction hanyalah sebuah protokol yang hanya memiliki satu metode - jalankan. Apple umumnya menyukai tema bioskop, beraksi di sini sebagai "kamera, motor!". "Motor" ini hanyalah sebuah aksi, dan bukan hanya nama yang digunakan. Metode menjalankan berarti memulai tindakan yang dapat memulai, menjalankan, dan mengakhiri, yang merupakan yang paling penting. Metode ini sangat umum, hanya memiliki event string, dan yang lainnya bisa dari jenis apa pun. Di ObjC, ini semua id dan NSDictionary normal.

Ada kelas di dalam UIKit yang memenuhi protokol CAAction. Yang pertama adalah animasi. Pertama, kita tahu bahwa animasi dapat ditambahkan ke layer, tetapi ini adalah hal yang sangat rendah. Abstraksi tingkat tinggi di atasnya adalah menjalankan aksi dengan parameter yang diperlukan dengan layer.
Pengecualian penting kedua adalah NSNull. Kita tahu bahwa dia tidak dapat dipanggil dengan metode apa pun, tetapi dia memenuhi protokol CAAction, dan ini dilakukan untuk mencari CAAction secara berlapis-lapis.

Seperti yang kami katakan sebelumnya, UIView adalah delegasi untuk CALayer, dan salah satu metode delegasi adalah aksi (untuk: forKey :). Lapisan memiliki metode, aksi forKey.

Kita bisa menyebutnya kapan saja di layer, dan kapan saja itu akan memberikan tindakan yang benar atau nihil, karena itu juga bisa memberi. Algoritma adalah pencarian yang sangat tidak biasa. Kodesemu ditulis di sini, mari kita lihat garis-garisnya. Setelah menerima pesan seperti itu, ia pertama kali berkonsultasi dengan delegasi. Seorang delegasi dapat mengembalikan nihil, yang berarti bahwa pencarian harus dilanjutkan di tempat lain, atau mungkin mengembalikan tindakan yang valid, objek yang valid yang memenuhi protokol CAAction. Tetapi ada aturan logis: jika mengembalikan NSNull, yang memenuhi protokol ini, maka nanti akan dikonversi menjadi nihil. Artinya, jika kita mengembalikan Null, sebenarnya itu berarti "berhenti mencari." Tidak ada tindakan dan itu tidak perlu.
Tetapi ada yang berikut ini. Setelah dia berkonsultasi dengan delegasi dan delegasi kembali nihil, dia terus mencari. Pertama, dalam Actions dictionary, yang dimiliki layer, dan kemudian secara rekursif akan mencari di dalam style dictionary, di mana juga bisa ada kamus dengan kunci tindakan, di mana banyak tindakan dapat ditulis, dan ia juga akan dapat mencarinya secara rekursif. Jika tidak berhasil di sana, ia akan meminta kelas untuk tindakan default untuk metodeey, yang didefinisikan oleh CALayer dan hingga baru-baru ini mengembalikan sesuatu, tetapi akhir-akhir ini selalu mengembalikan nol di versi terbaru iOS.
Memahami teorinya. Mari kita lihat bagaimana semuanya diterapkan dalam praktik.
Ada acara, mereka punya kunci, beberapa tindakan terjadi pada acara ini. Pada dasarnya, dua jenis peristiwa berbeda dapat dibedakan. Yang pertama adalah animasi dari properti yang disimpan. Misalkan ketika kita memanggil Viewcolor = red on View, secara teori dimungkinkan untuk menghidupkan.

Apa laporan tentang pola tanpa sirkuit? Saya menggambar beberapa. UIView memiliki beberapa jenis antarmuka yang telah kami tentukan untuk subclass atau yang diterima dari sistem dengan acara. Tugas UIView adalah untuk meminta tindakan yang diinginkan, memperbarui penyimpanan internal dan meluncurkan tindakan yang terjadi. Urutan ini sangat penting sehubungan dengan permintaan: tindakan, hanya kemudian memperbarui tindakan, dan hanya kemudian memperbarui toko dan tindakan.

Apa yang terjadi jika di UIView kami memperbarui backgroundColor. Kita tahu bahwa di UIView, semua yang terkait dengan tampilan di layar masih merupakan proxy untuk CALayer. Dia menyembunyikan semua yang dia terima, untuk berjaga-jaga, tetapi pada saat yang sama semuanya menyiarkan CALayer, dan dia berurusan dengan semua logika lebih lanjut tentang CALayer. Apa yang terjadi di dalam CALayer ketika menerima tugas untuk mengubah latar belakang? Semuanya sedikit lebih rumit di sini.

Sebagai permulaan, ia akan meminta tindakan. Dan penting untuk memahami bahwa tindakan akan diminta terlebih dahulu. Ini akan memungkinkan Anda untuk bertanya kepada CALayer tentang nilainya saat ini, termasuk backgroundColor, pada saat membuat tindakan, hanya kemudian toko akan diperbarui, dan ketika tindakan yang diterima menerima perintah jalankan, ia akan dapat berkonsultasi dengan CALayer dan mendapatkan nilai-nilai baru. Dengan demikian, ia akan memiliki yang lama dan yang baru, dan ini akan memungkinkannya untuk membuat animasi, jika perlu.
Tetapi ada satu fitur di UIView, jika kita mengubah backgroundColor di UIView, jika kita melakukan ini di blok animasi, maka itu animasi, dan jika itu di luar blok animasi, itu tidak dianimasikan.

Semuanya sangat sederhana, tidak ada keajaiban. Tapi ingatlah bahwa UIView adalah delegasi ke CALayer, ia memiliki metode seperti itu. Semuanya sangat sederhana.
Jika metode ini dijalankan di blok animasi, maka ia akan mengembalikan beberapa jenis tindakan. Jika di luar blok animasi, metode ini akan mengembalikan NSNull, yang berarti tidak ada yang perlu dianimasikan. , 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 . . โ . , โ .
, . .
. , , : , -, .
, , . . , UIKit , . . , , , . Terima kasih atas perhatian anda