Membuat tampilan kustom menjadi interaktif

Mencoba cara Compose
Jetpack Compose adalah toolkit UI yang direkomendasikan untuk Android. Pelajari cara menggunakan tata letak di Compose.

Menggambar UI hanyalah satu bagian dari membuat tampilan kustom. Anda juga perlu membuat tampilan Anda merespons input pengguna dengan cara yang sangat mirip dengan tindakan nyata yang Anda tiru.

Buat objek di aplikasi Anda bertindak seperti objek sungguhan. Misalnya, jangan biarkan gambar di aplikasi Anda muncul dan muncul kembali di tempat lain, karena objek di dunia nyata jangan lakukan itu. Sebagai gantinya, pindahkan gambar dari satu tempat ke lain.

Pengguna merasakan bahkan perilaku atau perasaan halus di antarmuka dan bereaksi paling baik terhadap halus yang meniru dunia nyata. Misalnya, saat pengguna melemparkan objek UI, memberi mereka rasa inersia di awal yang menunda gerakan. Di bagian akhir gerak, beri mereka momentum yang membawa objek melampaui ayunkan jari.

Halaman ini menunjukkan cara menggunakan fitur framework Android untuk menambahkan perilaku di dunia nyata ini pada tampilan kustom Anda.

Anda dapat menemukan informasi tambahan yang terkait di Ringkasan peristiwa input dan Animasi properti ringkasan.

Menangani gestur input

Seperti banyak framework UI lainnya, Android mendukung model peristiwa input. Pengguna berubah menjadi peristiwa yang memicu callback, dan Anda bisa mengganti callback untuk menyesuaikan cara aplikasi merespons pengguna. Input yang paling umum di 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 mendefinisikan interaksi dalam hal {i>gesture <i}seperti mengetuk, menarik, mendorong, mengayunkan jari, dan melakukan zoom. Untuk mengonversi kejadian sentuh mentah menjadi gestur, Android menyediakan GestureDetector.

Membuat GestureDetector dengan meneruskan instance class yang mengimplementasikan GestureDetector.OnGestureListener. Jika Anda hanya ingin memproses beberapa {i>gestures, <i} Anda dapat memperluas GestureDetector.SimpleOnGestureListener bukan menerapkan GestureDetector.OnGestureListener dalam antarmuka berbasis web yang sederhana. Misalnya, kode ini membuat class yang memperluas GestureDetector.SimpleOnGestureListener dan penggantian 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, selalu menerapkan onDown() yang menampilkan true. Hal ini diperlukan karena semua {i>gesture <i} diawali dengan pesan onDown(). Jika Anda mengembalikan false dari onDown(), sebagai GestureDetector.SimpleOnGestureListener, sistem menganggap Anda ingin mengabaikan sisa {i>gesture <i}tersebut, dan metode lainnya GestureDetector.OnGestureListener tidak dipanggil. Hanya pengembalian false dari onDown() jika Anda ingin mengabaikan seluruh {i>gesture <i}ini.

Setelah Anda menerapkan 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;
}

Saat Anda meneruskan peristiwa sentuh ke onTouchEvent() yang tidak dilakukan kenali sebagai bagian dari gestur, fungsi ini akan menampilkan false. Anda kemudian dapat menjalankan kode deteksi gestur khusus Anda sendiri.

Membuat gerakan yang masuk akal secara fisik

{i>Gesture <i}adalah cara yang ampuh untuk mengontrol perangkat layar sentuh, tetapi mereka kontra-intuitif dan sulit diingat kecuali mereka menghasilkan secara fisik hasil yang masuk akal.

Misalnya, Anda ingin mengimplementasikan gestur ayunkan jari horizontal yang menyetel item yang digambar dalam tampilan yang berputar di sekitar sumbu vertikalnya. Gestur ini masuk akal jika UI merespons dengan bergerak cepat ke arah ayunan, kemudian melambat, seolah-olah pengguna mendorong roda gila dan memutarnya.

Dokumentasi tentang cara menganimasikan scroll gestur memberikan penjelasan mendetail tentang cara menerapkan scoll Anda sendiri perilaku model. Namun, menyimulasikan nuansa roda inovasi bukanlah hal yang sepele. Banyak langkah fisika dan matematika diperlukan untuk membuat model roda inovasi bekerja dengan benar. Untungnya, Android menyediakan class helper untuk menyimulasikan hal ini dan perilaku lainnya. Tujuan Scroller adalah dasar untuk menangani gestur ayunkan jari gaya roda inovasi.

Untuk mulai melempar, panggil fling() dengan kecepatan awal serta nilai minimum dan maksimum x dan y fling-nya. Untuk nilai kecepatan, Anda dapat menggunakan nilai yang dihitung dengan 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 fling tersebut {i>gesture <i}ini. Setelah itu, update Scroller dengan memanggil Scroller.computeScrollOffset() dengan interval yang teratur. computeScrollOffset() memperbarui status internal objek Scroller dengan membaca waktu saat ini dan menggunakan model fisika untuk menghitung posisi x dan y pada baik. Telepon getCurrX() dan getCurrY() untuk mengambil nilai-nilai ini.

Sebagian besar tampilan meneruskan x dan y objek Scroller posisi langsung ke scrollTo(). Contoh ini sedikit berbeda: 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 untuk Anda, tetapi tidak menerapkan posisi tersebut secara otomatis ke tampilan Anda. Terapkan koordinat baru cukup sering untuk membuat animasi {i>scrolling<i} terlihat mulus. Ada dua cara untuk lakukan ini:

  • Paksa gambar ulang dengan memanggil postInvalidate() setelah memanggil fling(). Teknik ini mengharuskan Anda offset scroll dalam onDraw() dan memanggil postInvalidate() setiap kali offset scroll perubahan.
  • Siapkan ValueAnimator untuk menganimasikan durasi fling dan menambahkan pemroses untuk memproses pembaruan animasi dengan memanggil addUpdateListener(). Teknik ini memungkinkan Anda menganimasikan properti View.

Buat transisi Anda lancar

Pengguna mengharapkan UI modern untuk bertransisi dengan lancar antar-status: elemen UI menjadi jelas dan memudar, bukannya muncul dan menghilang, dan gerakan dimulai dan berakhir dengan lancar alih-alih memulai dan berhenti tiba-tiba. Android animasi properti membuat transisi yang lancar menjadi lebih mudah.

Untuk menggunakan sistem animasi, setiap kali properti mengubah hal yang memengaruhi tampilan tampilan, jangan mengubah properti secara langsung. Sebagai gantinya, gunakan ValueAnimator untuk melakukan perubahan. Dalam contoh berikut, memodifikasi komponen turunan yang dipilih dalam tampilan akan membuat seluruh proses diputar sehingga pointer pemilihan berada di tengah. ValueAnimator mengubah rotasi dalam jangka waktu 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 dari View dasar properti, membuat animasi jauh lebih mudah, karena tampilan memiliki ViewPropertyAnimator 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();