Menggambar UI hanyalah satu bagian dari membuat tampilan kustom. Anda juga harus membuat tampilan merespons input pengguna sedemikian rupa sehingga sangat mirip dengan tindakan sebenarnya yang dapat Anda tiru.
Buat objek dalam aplikasi Anda berfungsi seperti objek yang sebenarnya. Misalnya, jangan biarkan gambar di aplikasi Anda muncul dan muncul kembali di tempat lain, karena objek di dunia nyata tidak akan seperti itu. Sebagai gantinya, pindahkan gambar dari satu tempat ke tempat lain.
Pengguna merasakan perilaku atau nuansa yang halus dalam antarmuka dan bereaksi paling baik terhadap hal-hal kecil yang meniru dunia nyata. Misalnya, saat pengguna melemparkan objek UI, beri mereka rasa inersia di awal yang menunda gerakan. Di akhir gerakan, beri mereka momentum yang membawa objek melampaui ayunan tersebut.
Halaman ini menunjukkan cara menggunakan fitur framework Android untuk menambahkan perilaku nyata ini ke tampilan kustom Anda.
Anda dapat menemukan informasi terkait tambahan di Ringkasan peristiwa input dan Ringkasan animasi properti.
Menangani gestur input
Seperti banyak framework UI lainnya, Android mendukung model peristiwa input. Tindakan
pengguna berubah menjadi peristiwa yang memicu callback, dan Anda dapat mengganti
callback untuk menyesuaikan cara aplikasi merespons pengguna. Peristiwa input
yang paling umum dalam sistem Android adalah sentuh, yang memicu
onTouchEvent(android.view.MotionEvent)
.
Ganti metode ini untuk menangani peristiwa, seperti berikut:
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return super.onTouchEvent(event) }
Java
@Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
Peristiwa sentuh sendiri
tidak terlalu berguna. UI sentuh modern
menentukan interaksi dalam hal gestur seperti mengetuk, menarik, mendorong,
melempar, dan memperbesar/memperkecil. Untuk mengonversi peristiwa sentuh mentah menjadi gestur, Android
menyediakan
GestureDetector
.
Buat GestureDetector
dengan meneruskan instance class
yang mengimplementasikan
GestureDetector.OnGestureListener
.
Jika hanya ingin memproses beberapa gestur, Anda dapat memperluas
GestureDetector.SimpleOnGestureListener
,
bukan mengimplementasikan antarmuka
GestureDetector.OnGestureListener
. Misalnya, kode berikut membuat class yang memperluas
GestureDetector.SimpleOnGestureListener
dan mengganti
onDown(MotionEvent)
.
Kotlin
private val myListener = object : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { return true } } private val detector: GestureDetector = GestureDetector(context, myListener)
Java
class MyListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } } detector = new GestureDetector(getContext(), new MyListener());
Baik Anda menggunakan GestureDetector.SimpleOnGestureListener
atau tidak,
selalu implementasikan metode
onDown()
yang menampilkan true
. Hal ini diperlukan karena semua gestur
dimulai dengan pesan onDown()
. Jika Anda menampilkan false
dari onDown()
, seperti
GestureDetector.SimpleOnGestureListener
, sistem akan menganggap
Anda ingin mengabaikan seluruh gestur, dan metode lain dari
GestureDetector.OnGestureListener
tidak akan dipanggil. Hanya tampilkan
false
dari onDown()
jika Anda ingin mengabaikan seluruh
gestur.
Setelah mengimplementasikan GestureDetector.OnGestureListener
dan membuat
instance GestureDetector
, Anda dapat menggunakan
GestureDetector
untuk menafsirkan peristiwa sentuh yang Anda terima di
onTouchEvent()
.
Kotlin
override fun onTouchEvent(event: MotionEvent): Boolean { return detector.onTouchEvent(event).let { result -> if (!result) { if (event.action == MotionEvent.ACTION_UP) { stopScrolling() true } else false } else true } }
Java
@Override public boolean onTouchEvent(MotionEvent event) { boolean result = detector.onTouchEvent(event); if (!result) { if (event.getAction() == MotionEvent.ACTION_UP) { stopScrolling(); result = true; } } return result; }
Jika Anda meneruskan onTouchEvent()
peristiwa sentuh yang tidak
dikenali sebagai bagian dari gestur, peristiwa tersebut akan menampilkan false
. Selanjutnya, Anda dapat menjalankan kode deteksi gestur kustom Anda sendiri.
Buat gerakan yang masuk akal secara fisik
Gestur adalah cara efektif untuk mengontrol perangkat layar sentuh, tetapi kontra-intuitif dan sulit diingat kecuali jika memberikan hasil yang masuk akal secara fisik.
Misalnya, Anda ingin mengimplementasikan gestur ayunkan jari horizontal yang menyetel item yang digambar dalam tampilan yang berputar di sekitar sumbu vertikalnya. Gestur ini akan masuk akal jika UI merespons dengan bergerak cepat ke arah lemparan, lalu melambat, seolah-olah pengguna mendorong roda inovasi dan membuatnya berputar.
Dokumentasi tentang cara
menganimasikan gestur
scroll memberikan penjelasan mendetail tentang cara menerapkan perilaku
scoll Anda sendiri. Namun, menyimulasikan nuansa roda inovasi bukanlah hal yang mudah. Banyak fisika
dan matematika diperlukan untuk membuat model roda inovasi berfungsi dengan benar. Untungnya,
Android menyediakan class helper untuk menyimulasikan hal ini dan perilaku lainnya. Class
Scroller
adalah dasar untuk menangani gestur ayunkan jari bergaya roda inovasi.
Untuk memulai fling, panggil fling()
dengan kecepatan awal serta nilai x dan y minimum dan maksimum dari fling tersebut. Untuk nilai kecepatan, Anda dapat menggunakan nilai yang dihitung oleh
GestureDetector
.
Kotlin
fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { scroller.fling( currentX, currentY, (velocityX / SCALE).toInt(), (velocityY / SCALE).toInt(), minX, minY, maxX, maxY ) postInvalidate() return true }
Java
@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY); postInvalidate(); return true; }
Panggilan ke fling()
akan menyiapkan model fisika untuk gestur
ayunkan jari. Setelah itu, update Scroller
dengan memanggil
Scroller.computeScrollOffset()
secara berkala. computeScrollOffset()
memperbarui
status internal objek Scroller
dengan membaca waktu saat ini dan
menggunakan model fisika untuk menghitung posisi x dan y pada
waktu tersebut. Panggil
getCurrX()
dan
getCurrY()
untuk mengambil nilai ini.
Sebagian besar tampilan meneruskan posisi x dan y
objek Scroller
langsung ke
scrollTo()
.
Contoh ini sedikit berbeda: contoh ini menggunakan posisi x scroll saat ini
untuk menetapkan sudut rotasi tampilan.
Kotlin
scroller.apply { if (!isFinished) { computeScrollOffset() setItemRotation(currX) } }
Java
if (!scroller.isFinished()) { scroller.computeScrollOffset(); setItemRotation(scroller.getCurrX()); }
Class Scroller
menghitung posisi scroll secara otomatis, tetapi tidak
otomatis menerapkan posisi tersebut ke tampilan Anda. Terapkan koordinat baru
cukup sering agar animasi scroll terlihat halus. Ada dua cara untuk
melakukannya:
- Paksa penggambaran ulang dengan memanggil
postInvalidate()
setelah memanggilfling()
. Teknik ini mengharuskan Anda menghitung offset scroll dionDraw()
dan memanggilpostInvalidate()
setiap kali offset scroll berubah. - Siapkan
ValueAnimator
untuk menganimasikan selama ayunan jari dan tambahkan pemroses untuk memproses update animasi dengan memanggiladdUpdateListener()
. Teknik ini memungkinkan Anda menganimasikan propertiView
.
Buat transisi yang lancar
Pengguna mengharapkan UI modern bertransisi dengan lancar antar-status: elemen UI memudar dan keluar, bukan muncul dan menghilang, serta gerakan dimulai dan berakhir dengan lancar, bukan memulai dan berhenti tiba-tiba. Framework animasi properti Android membuat transisi yang lancar lebih mudah.
Untuk menggunakan sistem animasi, setiap kali properti berubah yang memengaruhi
tampilan tampilan Anda, jangan mengubah properti secara langsung. Sebagai gantinya, gunakan
ValueAnimator
untuk melakukan perubahan. Pada contoh berikut,
mengubah komponen turunan yang dipilih dalam tampilan akan membuat seluruh tampilan yang dirender
berputar sehingga pointer pemilihan dipusatkan.
ValueAnimator
mengubah rotasi selama periode beberapa ratus milidetik, bukan langsung menetapkan nilai rotasi baru.
Kotlin
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply { setIntValues(targetAngle) duration = AUTOCENTER_ANIM_DURATION start() }
Java
autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0); autoCenterAnimator.setIntValues(targetAngle); autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION); autoCenterAnimator.start();
Jika nilai yang ingin Anda ubah adalah salah satu properti View
dasar, melakukan animasi akan menjadi lebih mudah lagi, karena tampilan memiliki
ViewPropertyAnimator
bawaan yang dioptimalkan untuk animasi simultan beberapa properti, seperti dalam
contoh berikut:
Kotlin
animate() .rotation(targetAngle) .duration = ANIM_DURATION .start()
Java
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();