Dokunup basın

Birçok composable, dokunma veya tıklama için yerleşik desteğe sahiptir ve bir onClick lambda içerir. Örneğin, yüzeylerle etkileşim için uygun olan tüm Materyal Tasarım davranışlarını içeren tıklanabilir bir Surface oluşturabilirsiniz:

Surface(onClick = { /* handle click */ }) {
    Text("Click me!", Modifier.padding(24.dp))
}

Ancak tıklamalar, kullanıcıların composable'larla etkileşim kurmasının tek yolu değildir. Bu sayfada, tek bir işaretçi içeren ve bu işaretçinin konumunun, ilgili etkinliğin işlenmesi açısından önemli olmadığı hareketler ele alınmaktadır. Aşağıdaki tabloda bu hareket türleri listelenmiştir:

Hareket

Açıklama

Dokunun (veya tıklayın)

İşaretçi önce aşağı, sonra yukarı hareket eder.

İki kez dokunma

İşaretçi aşağı, yukarı, aşağı, yukarı hareket ediyor

Uzun basma

İşaretçi aşağı iner ve daha uzun süre basılı tutulur

Basın

İşaretçi aşağı gider

Dokunma veya tıklama işlemine yanıt verme

clickable, composable'ın dokunma veya tıklamalara tepki vermesini sağlayan, en çok tercih edilen bir değiştiricidir. Bu değiştirici, odaklanma, fare ve ekran kalemiyle üzerine gelme desteği ve basıldığında özelleştirilebilir bir görsel gösterge gibi ek özellikler de ekler. Değiştirici, kelimenin en geniş anlamıyla "tıklamalara" yanıt verir. Bu tıklamalar yalnızca fare veya parmakla değil, klavye girişiyle ya da erişilebilirlik hizmetleri kullanılırken yapılan tıklama etkinliklerini de kapsar.

Kullanıcıların tıkladığında tam ekran olarak gösterilen bir resim ızgarası düşünün:

Bu davranışı uygulamak için ızgaradaki her öğeye clickable değiştiricisini ekleyebilirsiniz:

@Composable
private fun ImageGrid(photos: List<Photo>) {
    var activePhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
    LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
        items(photos, { it.id }) { photo ->
            ImageItem(
                photo,
                Modifier.clickable { activePhotoId = photo.id }
            )
        }
    }
    if (activePhotoId != null) {
        FullScreenImage(
            photo = photos.first { it.id == activePhotoId },
            onDismiss = { activePhotoId = null }
        )
    }
}

clickable değiştiricisi ek davranış da ekler:

  • Kullanıcı composable'a dokunduğunda varsayılan olarak dalga efekti çizen interactionSource ve indication. Bunları nasıl özelleştireceğinizi Kullanıcı etkileşimlerini işleme sayfasından öğrenebilirsiniz.
  • Semantik bilgilerini ayarlayarak erişilebilirlik hizmetlerinin öğeyle etkileşim kurmasına olanak tanır.
  • Odaklanmaya ve etkileşim için Enter veya d-pad'in ortasına basmaya izin vererek klavye ya da kontrol çubuğu etkileşimini destekler.
  • Öğeyi fareyle üzerine gelinebilir hale getirin. Böylece fare veya ekran kalemiyle üzerine gelindiğinde yanıt verir.

Bağlam menüsünü göstermek için uzun basın

combinedClickable, normal tıklama davranışına ek olarak iki kez dokunma veya uzun basma davranışı eklemenize olanak tanır. Kullanıcı bir ızgara resmine dokunup basılı tuttuğunda bağlam menüsü göstermek için combinedClickable kullanabilirsiniz:

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

En iyi uygulama olarak, kullanıcı öğelere uzun bastığında dokunsal geribildirim eklemeniz gerekir. Bu nedenle snippet, performHapticFeedback çağrısını içerir.

Scrim'e dokunarak composable'ı kapatma

Yukarıdaki örneklerde clickable ve combinedClickable, composable'larınıza faydalı işlevler ekler. Etkileşimde görsel bir gösterge sunar, fareyle üzerine gelindiğinde yanıt verir ve odak, klavye ve erişilebilirlik desteği içerir. Ancak bu ek davranış her zaman istenmeyebilir.

Resim ayrıntıları ekranına bakalım. Arka plan yarı şeffaf olmalı ve kullanıcı, ayrıntı ekranını kapatmak için bu arka plana dokunabilmelidir:

Bu durumda, arka planın etkileşimle ilgili görsel bir göstergesi olmamalı, fareyle üzerine gelmeye yanıt vermemeli, odaklanılabilir olmamalı ve klavye ile erişilebilirlik etkinliklerine verdiği yanıt, tipik bir composable'ın yanıtından farklı olmalıdır. clickable davranışını uyarlamaya çalışmak yerine daha düşük bir soyutlama düzeyine inebilir ve pointerInput değiştiricisini doğrudan detectTapGestures yöntemiyle birlikte kullanabilirsiniz:

@Composable
private fun Scrim(onClose: () -> Unit, modifier: Modifier = Modifier) {
    val strClose = stringResource(R.string.close)
    Box(
        modifier
            // handle pointer input
            .pointerInput(onClose) { detectTapGestures { onClose() } }
            // handle accessibility services
            .semantics(mergeDescendants = true) {
                contentDescription = strClose
                onClick {
                    onClose()
                    true
                }
            }
            // handle physical keyboard input
            .onKeyEvent {
                if (it.key == Key.Escape) {
                    onClose()
                    true
                } else {
                    false
                }
            }
            // draw scrim
            .background(Color.DarkGray.copy(alpha = 0.75f))
    )
}

pointerInput değiştiricisinin anahtarı olarak onClose lambda'yı iletirsiniz. Bu, lambda'yı otomatik olarak yeniden yürütür ve kullanıcı scrim'e dokunduğunda doğru geri çağırmanın çağrılmasını sağlar.

Yakınlaştırmak için iki kez dokunun

Bazen clickable ve combinedClickable, etkileşime doğru şekilde yanıt vermek için yeterli bilgi içermez. Örneğin, composable'ların, etkileşimin gerçekleştiği composable sınırları içindeki konuma erişmesi gerekebilir.

Resim ayrıntıları ekranına tekrar bakalım. En iyi uygulamalardan biri, iki kez dokunarak resmin yakınlaştırılabilmesini sağlamaktır:

Videoda gördüğünüz gibi, dokunma etkinliğinin gerçekleştiği konumda yakınlaştırma yapılıyor. Resmin sol tarafını yakınlaştırdığımızda elde ettiğimiz sonuç, sağ tarafını yakınlaştırdığımızda elde ettiğimiz sonuçtan farklıdır. Dokunma konumunu hesaplamamıza dahil etmek için pointerInput değiştiricisini detectTapGestures ile birlikte kullanabiliriz:

var zoomed by remember { mutableStateOf(false) }
var zoomOffset by remember { mutableStateOf(Offset.Zero) }
Image(
    painter = rememberAsyncImagePainter(model = photo.highResUrl),
    contentDescription = null,
    modifier = modifier
        .pointerInput(Unit) {
            detectTapGestures(
                onDoubleTap = { tapOffset ->
                    zoomOffset = if (zoomed) Offset.Zero else
                        calculateOffset(tapOffset, size)
                    zoomed = !zoomed
                }
            )
        }
        .graphicsLayer {
            scaleX = if (zoomed) 2f else 1f
            scaleY = if (zoomed) 2f else 1f
            translationX = zoomOffset.x
            translationY = zoomOffset.y
        }
)