Dokunup basın

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

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

Ancak kullanıcıların, bileşenlerle etkileşime geçmesinin tek yolu tıklama 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

Dokunma (veya tıklama)

İşaretçi aşağı ve sonra yukarı gider

İki kez dokunun

İşaretçi aşağı, yukarı, aşağı, yukarı gider

Uzun basma

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

Basın

İşaretçi aşağı gider

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

clickable, bir bileşenin dokunma veya tıklama işlemlerine tepki vermesini sağlayan yaygın bir değiştiricidir. Bu değiştirici, odaklanma, fare ve ekran kalemi üzerine gelme desteği ve basıldığında özelleştirilebilir görsel gösterge gibi ek özellikler de ekler. Değiştirici, "tıklamalara" kelimenin en geniş anlamıyla yanıt verir. Yalnızca fare veya parmakla değil, klavye girişi aracılığıyla veya erişilebilirlik hizmetleri kullanılırken gerçekleşen tıklama etkinliklerine de yanıt verir.

Kullanıcının tıkladığı bir resmin tam ekran gösterildiği bir resim ızgarası düşünün:

Bu davranışı uygulamak için clickable değiştiriciyi ızgaradaki her öğeye 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ştirici, ek davranış da ekler:

  • interactionSource ve indication, kullanıcı composable'a dokunduğunda varsayılan olarak bir dalga çizer. Bunları nasıl özelleştireceğinizi Kullanıcı etkileşimlerini yönetme sayfasında öğrenebilirsiniz.
  • Erişilebilirlik hizmetlerinin, anlam bilgisini ayarlayarak öğeyle etkileşime geçmesine olanak tanır.
  • Odaklanma ve Enter tuşuna veya d-pad'in ortasına basarak etkileşime izin vererek klavye veya kontrol çubuğuyla etkileşimi destekler.
  • Fare veya ekran kaleminin üzerine geldiğinde yanıt vermesi için öğeyi fareyle üzerine gelinebilir hale getirin.

Bağlama dayalı içerik menüsü göstermek için uzun basın

combinedClickable, normal tıklama davranışına ek olarak iki kez dokunma veya uzun basma davranışı eklemenizi sağlar. Kullanıcı bir ızgara resmine dokunup basılı tuttuğunda içerik menüsü göstermek için combinedClickable simgesini 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 dokunma geri bildirimi eklemeniz gerekir. Bu nedenle snippet'te performHapticFeedback çağrısı yer alır.

Bir örtüye dokunarak bir bileşiği kapatma

Yukarıdaki örneklerde clickable ve combinedClickable, bileşenlerinize yararlı işlevler ekler. Etkileşimde görsel bir gösterge gösterir, fareyle üzerine gelindiğinde yanıt verir ve odak, klavye ve erişilebilirlik desteği içerir. Ancak bu ek davranış her zaman istenmez.

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

Bu durumda, bu arka planda etkileşimle ilgili herhangi bir görsel gösterge bulunmamalı, fareyle üzerine gelindiğinde yanıt verilmemeli, odaklanılabilir olmamalı ve klavye ile erişilebilirlik etkinliklerine verdiği yanıt, tipik bir kompozisyonun yanıtından farklı olmalıdır. clickable davranışını uyarlamaya çalışmak yerine daha düşük bir soyutlama düzeyine inebilir ve detectTapGestures yöntemiyle birlikte doğrudan pointerInput değiştiriciyi 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 lambdasını iletirsiniz. Bu işlem, lambda'yı otomatik olarak yeniden yürütür ve kullanıcı scrim'e dokunduğunda doğru geri çağırma işlevinin ç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, bileşenlerin etkileşimin gerçekleştiği bileşen sınırları içindeki konuma erişmesi gerekebilir.

Resim ayrıntıları ekranına tekrar göz atalım. En iyi uygulama, çift dokunarak resmi yakınlaştırmayı mümkün kılmaktır:

Videoda görebileceğiniz gibi, yakınlaştırma işlemi dokunma etkinliğinin konumu çevresinde gerçekleşir. Resmin sol kısmını yakınlaştırdığımızda elde edilen sonuç, sağ kısmını yakınlaştırdığımızdan 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
        }
)