Tarik lalu Lepas di Compose

1. Sebelum memulai

Codelab ini memberikan petunjuk praktis tentang dasar-dasar penerapan operasi tarik lalu lepas untuk Compose. Anda akan mempelajari cara mengaktifkan tampilan untuk ditarik dan dilepas, baik di dalam aplikasi maupun di berbagai aplikasi. Anda akan mempelajari cara menerapkan operasi tarik lalu lepas dalam aplikasi dan bahkan di berbagai aplikasi.

Prasyarat

Untuk menyelesaikan codelab ini, Anda memerlukan:

Yang akan Anda lakukan

Membuat aplikasi sederhana yang:

  • Mengonfigurasi composable agar dapat ditarik menggunakan pengubah dragAndDropSource
  • Mengonfigurasi composable untuk menjadi target lepas menggunakan pengubah dragAndDropTarget

Yang akan Anda butuhkan

2. Peristiwa tarik lalu lepas

Operasi tarik lalu lepas dapat dilihat sebagai peristiwa 4 tahap, yaitu sebagai berikut

  1. Dimulai : Sistem memulai operasi tarik lalu lepas sebagai respons terhadap gestur tarik pengguna.
  2. Melanjutkan : Pengguna terus menarik.
  3. Berakhir : Pengguna melepaskan operasi tarik di composable target lepas
  4. Tersedia : Sistem mengirimkan sinyal untuk mengakhiri operasi tarik lalu lepas.

Sistem mengirim peristiwa tarik di objek DragEvent. Objek DragEvent dapat berisi data berikut

  1. ActionType : Nilai tindakan peristiwa berdasarkan peristiwa siklus proses dari peristiwa tarik lalu lepas, misalnya ACTION_DRAG_STARTED, ACTION_DROP, dll.
  2. ClipData : Data sedang ditarik dan dienkapsulasi dalam objek ClipData
  3. ClipDescription : Informasi meta tentang objek ClipData
  4. Result : Hasil operasi tarik lalu lepas
  5. X : koordinat x dari lokasi objek yang ditarik saat ini
  6. Y : koordinat y dari lokasi objek yang ditarik saat ini

3. Penyiapan

Buat project baru dan pilih template "Empty Activity":

19da275afd995463.png

Biarkan semua parameter seperti default-nya.

Dalam codelab ini, kita akan menggunakan ImageView untuk mendemonstrasikan fungsi tarik lalu lepas. Mari tambahkan dependensi gradle library glide untuk menulis dan menyinkronkan project.

implementation("com.github.bumptech.glide:compose:1.0.0-beta01")

Sekarang di MainActivity.kt , buat composable untuk Gambar yang akan berfungsi sebagai sumber tarik untuk tujuan kita

@Composable
fun DragImage(url: String) {
   GlideImage(model = url, contentDescription = "Dragged Image")
}

Buat juga gambar target Lepas.

@Composable
fun DropTargetImage(url: String) {
   val urlState = remember {mutableStateOf(url)}
   GlideImage(model = urlState.value, contentDescription = "Dropped Image")
}

Tambahkan composable kolom ke composable Anda untuk menyertakan dua gambar ini.

Column {
   DragImage(url = getString(R.string.source_url))
   DropTargetImage(url = getString(R.string.target_url))
}

Di tahap ini, kita memiliki MainActivity yang menampilkan dua gambar secara vertikal. Anda akan dapat melihat layar ini.

5e12c26cb2ad1068.png

4. Mengonfigurasi sumber Tarik

Mari tambahkan pengubah sumber Tarik lalu Lepas untuk composable DragImage kita

modifier = Modifier.dragAndDropSource {
   detectTapGestures(
       onLongPress = {
           startTransfer(
               DragAndDropTransferData(
                   ClipData.newPlainText("image uri", url)
               )
           )
       }
   )
}

Di sini, pengubah dragAndDropSource telah ditambahkan. Pengubah dragAndDropSource mengaktifkan fungsi tarik lalu lepas untuk setiap elemen yang diterapkan. Secara visual, elemen yang ditarik sebagai bayangan tarik mewakili elemen yang ditarik.

Pengubah dragAndDropSource menyediakan PointerInputScope untuk mendeteksi gestur tarik. Kita telah menggunakan detectTapGesture PointerInputScope untuk mendeteksi longPress yang merupakan gestur tarik.

Metode onLongPress yang kita gunakan untuk memulai transfer data yang sedang ditarik.

startTransfer memulai sesi tarik lalu lepas dengan transferData sebagai data yang akan ditransfer saat penyelesaian gestur. Diperlukan data yang dienkapsulasi di DragAndDropTransferData yang memiliki 3 kolom

  1. Clipdata: data aktual yang akan ditransfer
  2. flags : tanda untuk mengontrol operasi tarik lalu lepas
  3. localState : status lokal sesi saat menarik aktivitas yang sama

ClipData adalah objek kompleks yang berisi item dari berbagai jenis seperti teks, markup, audio, video, dll. Untuk tujuan codelab ini, kita menggunakan imageurl sebagai item di ClipData.

Bagus, sekarang tampilan kita dapat ditarik.

415dcef002492e61.gif

5. Konfigurasi untuk Tarik

Agar dapat menerima item yang dilepas, tampilan harus menambahkan dragAndDropTarget modifier

Modifier.dragAndDropTarget(
   shouldStartDragAndDrop = {
       // condition to accept dragged item
   },
   target = // DragAndDropTarget
   )
)

dragAndDropTarget adalah pengubah yang memungkinkan data ditarik dalam composable. Pengubah ini memiliki dua parameter

  1. shouldStartDragAndDrop : Mengizinkan Composable untuk memutuskan apakah ingin menerima dari sesi tarik lalu lepas tertentu dengan memeriksa DragAndDropEvent yang memulai sesi tersebut.
  2. target : DragAndDropTarget yang akan menerima peristiwa untuk sesi tarik lalu lepas tertentu.

Mari tambahkan kondisi saat kita ingin meneruskan peristiwa tarik ke DragAndDropTarget.

shouldStartDragAndDrop = { event ->
   event.mimeTypes()
       .contains(ClipDescription.MIMETYPE_TEXT_PLAIN)
}

Kondisi yang ditambahkan di sini hanya untuk mengizinkan tindakan lepas jika minimal salah satu item yang diseret adalah teks biasa. Target operasi lepas tidak akan diaktifkan jika tidak ada item yang berupa teks biasa.

Untuk parameter target, buat objek DragAndDropTarget yang menangani sesi lepas.

val dndTarget = remember{
   object : DragAndDropTarget{
       // handle Drag event
   }
}

DragAndDropTarget memiliki callback yang harus diganti untuk setiap tahap dalam sesi tarik lalu lepas.

  1. onDrop : Item telah dilepas di dalam DragAndDropTarget ini, dan menampilkan nilai benar untuk menunjukkan bahwa DragAndDropEvent digunakan, sedangkan nilai salah menunjukkan bahwa item ditolak
  2. onStarted : Sesi tarik lalu lepas baru saja dimulai dan DragAndDropTarget ini memenuhi syarat untuk menerimanya. Tindakan ini memberikan peluang untuk menetapkan status DragAndDropTarget sebagai persiapan untuk menggunakan sesi tarik lalu lepas.
  3. onEntered : Item yang dihapus telah memasuki batas DragAndDropTarget ini.
  4. onMoved : Item yang dihapus telah dipindahkan dalam batas DragAndDropTarget ini.
  5. onExited : Item yang dihapus telah dipindahkan ke luar batas DragAndDropTarget ini.
  6. onChanged : Peristiwa di sesi tarik lalu lepas saat ini telah berubah dalam batas DragAndDropTarget. Mungkin tombol pengubah telah ditekan atau dilepaskan
  7. onEnded : Sesi tarik lalu lepas telah selesai. Semua instance DragAndDropTarget dalam hierarki yang sebelumnya menerima peristiwa onStarted akan menerima peristiwa ini. Tindakan ini memberikan peluang untuk mereset status DragAndDropTarget.

Mari tentukan apa yang terjadi saat item dilepas dalam composable target.

override fun onDrop(event: DragAndDropEvent): Boolean {
   val draggedData = event.toAndroidDragEvent().clipData.getItemAt(0).text
   urlState.value = draggedData.toString()
   return true
}

Dalam fungsi onDrop, kita mengekstrak item ClipData dan menetapkannya ke URL gambar, serta menampilkan nilai benar untuk menunjukkan bahwa sesi tarik telah ditangani dengan benar.

Jangan izinkan plug menetapkan instance DragAndDropTarget ini ke parameter target pengubah dragAndDropTarget

Modifier.dragAndDropTarget(
   shouldStartDragAndDrop = { event ->
       event.mimeTypes()
           .contains(ClipDescription.MIMETYPE_TEXT_PLAIN)
   },
   target = dndTarget
)

Bagus, sekarang kita dapat melakukan operasi tarik lalu lepas.

277ed56f80460dec.gif

Meskipun kita telah menambahkan fungsi tarik lalu lepas, sulit untuk memahami apa yang terjadi secara visual. Mari kita ubah.

Untuk melepaskan composable target, mari terapkan ColorFilter ke gambar

var tintColor by remember {
   mutableStateOf(Color(0xffE5E4E2))
}

Setelah menentukan warna tint, tambahkan ColorFilter ke gambar

GlideImage(
   colorFilter = ColorFilter.tint(color = backgroundColor,
       blendMode = BlendMode.Modulate),
   // other params
)

Kita ingin menerapkan tint ke warna ke gambar saat item yang ditarik memasuki area target Lepas. Untuk itu, kita dapat mengganti callback onEntered

override fun onEntered(event: DragAndDropEvent) {
   super.onEntered(event)
   tintColor = Color(0xff00ff00)
}

Selain itu, saat pengguna menarik keluar dari area target, kita harus melakukan penggantian ke filter warna asli. Untuk itu, kita harus mengganti callback onExited

override fun onExited(event: DragAndDropEvent) {
   super.onEntered(event)
   tintColor = Color(0xffE5E4E2)
}

Setelah berhasil menyelesaikan operasi tarik lalu lepas, kita juga dapat mengembalikan ke ColorFilter asli

override fun onEnded(event: DragAndDropEvent) {
   super.onEntered(event)
   tintColor = Color(0xffE5E4E2)
}

Pada akhirnya, composable drop akan terlihat seperti ini

@Composable
fun DropTargetImage(url: String) {
   val urlState = remember {
       mutableStateOf(url)
   }
   var tintColor by remember {
       mutableStateOf(Color(0xffE5E4E2))
   }
   val dndTarget = remember {
       object : DragAndDropTarget {
           override fun onDrop(event: DragAndDropEvent): Boolean {
               val draggedData = event.toAndroidDragEvent()
                   .clipData.getItemAt(0).text
               urlState.value = draggedData.toString()
               return true
           }

           override fun onEntered(event: DragAndDropEvent) {
               super.onEntered(event)
               tintColor = Color(0xff00ff00)
           }
           override fun onEnded(event: DragAndDropEvent) {
               super.onEntered(event)
               tintColor = Color(0xffE5E4E2)
           }
           override fun onExited(event: DragAndDropEvent) {
               super.onEntered(event)
               tintColor = Color(0xffE5E4E2)
           }

       }
   }
   GlideImage(
       model = urlState.value,
       contentDescription = "Dropped Image",
       colorFilter = ColorFilter.tint(color = tintColor,
           blendMode = BlendMode.Modulate),
       modifier = Modifier
           .dragAndDropTarget(
               shouldStartDragAndDrop = { event ->
                   event
                       .mimeTypes()
                       .contains(ClipDescription.MIMETYPE_TEXT_PLAIN)
               },
               target = dndTarget
           )
   )
}

Bagus, kita dapat menambahkan isyarat visual untuk operasi tarik lalu lepas.

6be7e749d53d3e7e.gif

6. Selamat!

Compose untuk Tarik lalu Lepas menyediakan antarmuka yang mudah untuk menerapkan fungsi tarik lalu lepas di Compose menggunakan pengubah untuk tampilan.

Di Ringkasan, Anda telah mempelajari cara menerapkan operasi tarik lalu lepas menggunakan compose. Pelajari dokumentasi lebih lanjut.

Pelajari lebih lanjut