Menggambar UI hanyalah satu bagian dari membuat tampilan kustom. Anda juga harus membuat tampilan merespons input pengguna dengan cara yang sangat mirip dengan tindakan nyata yang Anda tiru.
Buat objek di aplikasi Anda bertindak seperti objek sebenarnya. Misalnya, jangan biarkan gambar dalam aplikasi Anda muncul dan muncul kembali di tempat lain, karena objek di dunia nyata tidak melakukan hal itu. Sebagai gantinya, pindahkan gambar dari satu tempat ke tempat lain.
Pengguna merasakan bahkan perilaku atau perasaan halus di antarmuka dan bereaksi paling baik terhadap kehalusan yang meniru dunia nyata. Misalnya, saat pengguna melemparkan objek UI, berikan kesan inersia di awal yang menunda gerakan. Di akhir gerakan, beri pengguna kesan momentum yang membawa objek melampaui lemparan tersebut.
Halaman ini menunjukkan cara menggunakan fitur framework Android untuk menambahkan perilaku dunia nyata ini ke tampilan kustom Anda.
Anda dapat menemukan informasi terkait lainnya 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 Anda merespons pengguna. Peristiwa input yang paling umum
dalam sistem Android adalah sentuh, yang memicu
onTouchEvent(android.view.MotionEvent)
.
Ganti metode ini untuk menangani peristiwa, sebagai 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 itu sendiri tidak terlalu berguna. UI sentuh modern
menentukan interaksi dalam hal gestur seperti mengetuk, menarik, mendorong,
mengayunkan, dan zoom. 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 ini 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 terapkan metode
onDown()
yang menampilkan true
. 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
GestureDetector.OnGestureListener
tidak akan dipanggil. Hanya tampilkan
false
dari onDown()
jika Anda ingin mengabaikan seluruh
gestur.
Setelah menerapkan GestureDetector.OnGestureListener
dan membuat
instance GestureDetector
, Anda dapat menggunakan
GestureDetector
untuk menafsirkan peristiwa sentuh yang diterima 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; }
Saat Anda meneruskan onTouchEvent()
peristiwa sentuh yang tidak
dikenali sebagai bagian dari gestur, false
akan ditampilkan. Anda kemudian dapat menjalankan
kode deteksi gestur kustom Anda sendiri.
Membuat gerakan yang masuk akal secara fisik
Gestur adalah cara ampuh untuk mengontrol perangkat layar sentuh, tetapi mungkin 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 digambar dalam tampilan yang berputar di sekitar sumbu vertikalnya. Gestur ini masuk akal jika UI merespons dengan bergerak cepat ke arah ayunan, lalu melambat, seolah-olah pengguna mendorong flywheel dan memutarnya.
Dokumentasi tentang cara
menganimasikan gestur
scroll memberikan penjelasan mendetail tentang cara menerapkan perilaku
scoll Anda sendiri. Namun, menyimulasikan nuansa roda inovasi bukanlah hal yang sepele. 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 untuk 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 saat
itu. 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: mode ini menggunakan posisi scroll x saat ini
untuk menyetel 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. Menerapkan koordinat baru
cukup sering agar animasi scroll terlihat lancar. Ada dua cara untuk
melakukannya:
- Paksa gambar 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 durasi ayunan dan tambahkan pemroses untuk memproses pembaruan animasi dengan memanggiladdUpdateListener()
. Teknik ini memungkinkan Anda menganimasikan propertiView
.
Buat transisi Anda lancar
Pengguna mengharapkan UI modern bertransisi dengan lancar antar-status: elemen UI memudar dan memudar, bukan muncul dan menghilang, serta gerakan dimulai dan berakhir dengan lancar, bukan tiba-tiba memulai dan berhenti. Framework animasi properti Android membuat transisi yang lancar menjadi lebih mudah.
Untuk menggunakan sistem animasi, setiap kali properti mengubah hal yang memengaruhi
tampilan tampilan, jangan ubah properti secara langsung. Sebagai gantinya, gunakan
ValueAnimator
untuk melakukan perubahan. Dalam contoh berikut,
mengubah komponen turunan yang dipilih dalam tampilan akan membuat seluruh tampilan
yang dirender diputar sehingga pointer pemilihan berada di tengah.
ValueAnimator
mengubah rotasi selama 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 jauh lebih mudah, karena tampilan memiliki
ViewPropertyAnimator
bawaan yang dioptimalkan untuk animasi simultan beberapa properti, seperti pada
contoh berikut:
Kotlin
animate() .rotation(targetAngle) .duration = ANIM_DURATION .start()
Java
animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();