टैप करें और दबाएं

कई कंपोज़ेबल में टैप या क्लिक का बेहतर अनुभव मिलता है और इनमें onClick लैम्डा. उदाहरण के लिए, क्लिक किया जा सकने वाला ऐसा Surface बनाया जा सकता है जिसे इसमें सरफ़ेस के साथ इंटरैक्शन के लिए सही सभी मटीरियल डिज़ाइन व्यवहार शामिल होता है:

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

हालांकि, कंपोज़ेबल के साथ इंटरैक्ट करने के लिए, उपयोगकर्ता सिर्फ़ क्लिक ही नहीं कर सकते. यह पेज उन जेस्चर पर फ़ोकस करता है जिनमें सिंगल पॉइंटर शामिल होता है, जहां वह पॉइंटर उस इवेंट को मैनेज करने के लिए अहम नहीं है. नीचे दिए गए टेबल में इस तरह के जेस्चर की सूची होती है:

हाथ के जेस्चर

ब्यौरा

टैप करें (या क्लिक करें)

पॉइंटर नीचे और फिर ऊपर जाता है

दो बार टैप करें

पॉइंटर नीचे, ऊपर, नीचे, ऊपर जाता है

देर तक दबाएं

पॉइंटर नीचे चला जाता है और काफ़ी देर तक दबाकर रहता है

प्रेस

पॉइंटर नीचे चला जाता है

टैप या क्लिक पर प्रतिक्रिया दें

clickable आम तौर पर इस्तेमाल किया जाने वाला ऐसा मॉडिफ़ायर है जो किसी कीवर्ड के लिए कंपोज़ेबल रिऐक्शन बनाता है टैप या क्लिक. यह मॉडिफ़ायर, अतिरिक्त सुविधाएं भी जोड़ता है, जैसे- फ़ोकस, माउस और स्टाइलस होवरिंग, और एक कस्टमाइज़ करने योग्य विज़ुअल संकेत दबाया गया. कार्रवाई बदलने वाली कुंजी "क्लिक" का जवाब देती है का अनुभव सबसे अच्छा है-- नहीं केवल माउस या उंगली से, लेकिन कीबोर्ड इनपुट के माध्यम से या जब आप ईवेंट पर क्लिक करते हैं, में बताया गया है.

इमेज के एक ग्रिड के बारे में सोचें. इसमें किसी उपयोगकर्ता को दिखाए जाने पर इमेज फ़ुल-स्क्रीन में दिखती है तो उस पर क्लिक करता है:

इसे लागू करने के लिए, ग्रिड के हर आइटम में clickable मॉडिफ़ायर जोड़ा जा सकता है व्यवहार:

@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 मॉडिफ़ायर भी अतिरिक्त काम करता है:

  • interactionSource और indication, जो डिफ़ॉल्ट रूप से एक रिपल बनाते हैं उपयोगकर्ता, कंपोज़ेबल पर टैप करता है. उपयोगकर्ता को हैंडल करने से जुड़ी सेटिंग पर जाकर, इन्हें पसंद के मुताबिक बनाने का तरीका जानें इंटरैक्शन पेज पर जाकर इसकी जानकारी दी जा सकती है.
  • यह सेटिंग, सुलभता सेवाओं को एलिमेंट के साथ इंटरैक्ट करने की अनुमति देती है सिमैंटिक से जुड़ी जानकारी.
  • फ़ोकस करने और दबाकर रखने की अनुमति देकर कीबोर्ड या जॉयस्टिक इंटरैक्शन का समर्थन करता है इंटरैक्ट करने के लिए Enter या डी-पैड के बीच में.
  • एलिमेंट को होवर करने लायक बनाएं, ताकि वह माउस या स्टाइलस के कर्सर घुमाने पर काम करे उसके ऊपर.

संदर्भ का मेन्यू दिखाने के लिए, दबाकर रखें

combinedClickable की मदद से, दो बार टैप करने या दबाकर रखने की सुविधा जोड़ी जा सकती है क्लिक करने के सामान्य व्यवहार के अलावा. combinedClickable का इस्तेमाल करके, जब कोई उपयोगकर्ता ग्रिड इमेज को दबाकर रखता है, तब संदर्भ मेन्यू:

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 }
    )
}

सबसे सही तरीका यह है कि आप हैप्टिक फ़ीडबैक दें, जब उपयोगकर्ता एलिमेंट को लंबे समय तक दबाता है और यही वजह है कि स्निपेट में performHapticFeedback शुरू करना.

स्क्रिम पर टैप करके, किसी कंपोज़ेबल को खारिज करें

ऊपर दिए गए उदाहरण में, clickable और combinedClickable 'फ़ायदे' के बारे में बताते हैं आपके कंपोज़ेबल में मौजूद सुविधाओं के बारे में बात करते हैं. वे इंटरैक्शन पर एक विज़ुअल संकेत दिखाते हैं, कर्सर घुमाने पर रिस्पॉन्स में फ़ोकस, कीबोर्ड, और सुलभता की सुविधा शामिल होते हैं. लेकिन ऐसा होना ज़रूरी नहीं है.

आइए, इमेज की जानकारी वाली स्क्रीन पर नज़र डालते हैं. बैकग्राउंड आधा-पारदर्शी होना चाहिए साथ ही, उपयोगकर्ता के पास ज़्यादा जानकारी वाली स्क्रीन को खारिज करने के लिए, उस बैकग्राउंड पर टैप करने की सुविधा होनी चाहिए:

इस मामले में, उस बैकग्राउंड का कोई विज़ुअल संकेत नहीं होना चाहिए इंटरैक्शन, कर्सर घुमाने पर नहीं होना चाहिए, फ़ोकस करने लायक नहीं होना चाहिए, और कीबोर्ड और सुलभता इवेंट का रिस्पॉन्स, किसी सामान्य इवेंट के रिस्पॉन्स से अलग होता है कंपोज़ेबल. clickable के तरीके के हिसाब से काम करने के बजाय, उसे कम करें कम एब्सट्रैक्ट लेवल तक ले जाना चाहिए और सीधे pointerInput मॉडिफ़ायर का इस्तेमाल करना चाहिए यह तरीका detectTapGestures तरीके के साथ इस्तेमाल किया जाएगा:

@OptIn(ExperimentalComposeUiApi::class)
@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 मॉडिफ़ायर की कुंजी के तौर पर, आपने onClose lambda को पास किया है. यह यह पक्का करते हुए कि सही कॉलबैक को कॉल किया गया है, Lambda फ़ंक्शन को अपने-आप फिर से लागू करता है जब उपयोगकर्ता स्क्रिम पर टैप करता है.

ज़ूम करने के लिए दो बार टैप करें

कभी-कभी clickable और combinedClickable में पूरी जानकारी नहीं होती सही जवाब देने के लिए. उदाहरण के लिए, कंपोज़ेबल कंपोज़ेबल के दायरे में मौजूद उस पोज़िशन के ऐक्सेस की ज़रूरत होती है जहां इंटरैक्शन हुआ है.

इमेज की जानकारी वाली स्क्रीन पर दोबारा नज़र डालते हैं. सबसे सही तरीका यह है कि दो बार टैप करके इमेज को ज़ूम इन किया जा सकता है:

जैसा कि आप वीडियो में देख सकते हैं, टैप करने की जगह के आस-पास ज़ूम इन होता है इवेंट. इमेज के बाईं ओर ज़ूम इन करने पर, आपको अलग नतीजा मिलता है हिस्सा लेना है. हम pointerInput मॉडिफ़ायर का इस्तेमाल कॉम्बिनेशन में कर सकते हैं को detectTapGestures के साथ टैप स्थिति को अपने कैलकुलेशन:

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
        }
)