Wear OS के लिए, Compose में मौजूद सूचियां


Wear OS डिवाइसों पर, सूचियों की मदद से उपयोगकर्ता विकल्पों के सेट में से कोई आइटम चुन सकते हैं.

Wear OS वाले कई डिवाइसों में गोल स्क्रीन होती हैं. इस वजह से, स्क्रीन के सबसे ऊपर और सबसे नीचे दिखने वाले आइटम को देखना मुश्किल हो जाता है. इस वजह से, Compose for Wear OS में LazyColumn क्लास का एक वर्शन शामिल है, जिसे TransformingLazyColumn कहा जाता है. यह स्केलिंग और मॉर्फ़िंग ऐनिमेशन के साथ काम करता है. जब आइटम किनारों पर पहुंचते हैं, तो वे छोटे हो जाते हैं और धुंधले हो जाते हैं.

सुझाए गए स्केलिंग और स्क्रोलिंग इफ़ेक्ट लागू करने के लिए:

  1. Modifier.transformedHeight का इस्तेमाल करें, ताकि कंपोज़ फ़ंक्शन, स्क्रीन पर आइटम स्क्रोल होने पर ऊंचाई में होने वाले बदलाव का हिसाब लगा सके.
  2. आइटम के कॉन्टेंट को छोटा करने के साथ-साथ, विज़ुअल इफ़ेक्ट लागू करने के लिए transformation = SurfaceTransformation(transformationSpec) का इस्तेमाल करें.
  3. उन कॉम्पोनेंट के लिए कस्टम TransformationSpec का इस्तेमाल करें जो transformation को पैरामीटर के तौर पर नहीं लेते हैं. जैसे, Text.

इस एनिमेशन में दिखाया गया है कि स्क्रीन के सबसे ऊपर और सबसे नीचे पहुंचने पर, सूची का एलिमेंट कैसे स्केल होता है और उसका आकार कैसे बदलता है:

यहां दिए गए कोड स्निपेट में, TransformingLazyColumn लेआउट का इस्तेमाल करके सूची बनाने का तरीका बताया गया है. इससे ऐसा कॉन्टेंट बनाया जा सकता है जो Wear OS की अलग-अलग स्क्रीन साइज़ पर शानदार दिखता है.

स्निपेट में minimumVerticalContentPadding मॉडिफ़ायर का इस्तेमाल भी दिखाया गया है. आपको सूची के आइटम पर इसे सेट करना चाहिए, ताकि सूची के ऊपर और नीचे सही पैडिंग लागू की जा सके.

स्क्रोल इंडिकेटर दिखाने के लिए, ScreenScaffold और TransformingLazyColumn के बीच columnState शेयर करें:

val columnState = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
ScreenScaffold(
    scrollState = columnState
) { contentPadding ->
    TransformingLazyColumn(
        state = columnState,
        contentPadding = contentPadding
    ) {
        item {
            ListHeader(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding),
                transformation = SurfaceTransformation(transformationSpec)
            ) {
                Text(text = "Header")
            }
        }
        // ... other items
        item {
            Button(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding),
                transformation = SurfaceTransformation(transformationSpec),
                onClick = { /* ... */ },
                icon = {
                    Icon(
                        imageVector = Icons.Default.Build,
                        contentDescription = "build",
                    )
                },
            ) {
                Text(
                    text = "Build",
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
            }
        }
    }
}

स्नैप-एंड-फ़्लिंग इफ़ेक्ट जोड़ना

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

स्नैप-एंड-फ़्लिंग की सुविधा जोड़ने के लिए, flingBehavior पैरामीटर को TransformingLazyColumnDefaults.snapFlingBehavior(columnState) पर सेट करें. RotaryScrollableDefaults.snapBehavior(columnState) को मैच पर सेट करें. इसके लिए, RotaryScrollableDefaults.snapBehavior(columnState) का इस्तेमाल करें, ताकि फ़िज़िकल क्राउन या बेज़ल का इस्तेमाल करते समय एक जैसा अनुभव मिले.rotaryScrollableBehavior

val columnState = rememberTransformingLazyColumnState()
ScreenScaffold(scrollState = columnState) { contentPadding ->
    TransformingLazyColumn(
        state = columnState,
        flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState),
        rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState)
    ) {
        // ...
        // ...
    }
}

उल्टा लेआउट

डिफ़ॉल्ट रूप से, स्क्रोल की जा सकने वाली सूची, अपने सबसे ऊपरी किनारे पर ऐंकर होती है. अगर कोई उपयोगकर्ता किसी स्टैंडर्ड सूची के सबसे नीचे तक स्क्रोल करता है और सूची के आखिर में कोई नया आइटम जोड़ा जाता है, तो सूची में उपयोगकर्ता को मौजूदा आइटम दिखता रहता है. उदाहरण के लिए, अगर उपयोगकर्ता स्क्रीन पर सबसे नीचे मौजूद आइटम 10 को देख रहा है और आइटम 11 को जोड़ा जाता है, तो व्यू आइटम 10 पर ही फ़ोकस रहेगा. साथ ही, आइटम 11 मौजूदा व्यू के नीचे स्क्रीन से बाहर दिखेगा.

मैसेजिंग ऐप्लिकेशन या लाइव लॉग जैसे इस्तेमाल के उदाहरणों के लिए, आम तौर पर इस व्यवहार की ज़रूरत नहीं होती. जब नए आइटम आते हैं, तो आम तौर पर उपयोगकर्ता चाहते हैं कि अगर वे पहले से ही सूची के सबसे नीचे हैं, तो उन्हें तुरंत नया कॉन्टेंट दिखे. अगर कई आइटम एक साथ पहुंचते हैं, तो सूची में सबसे नए आइटम को सबसे नीचे दिखाया जाना चाहिए. इसका मतलब है कि कुछ आइटम तब तक नहीं दिखेंगे, जब तक उपयोगकर्ता वापस ऊपर की ओर स्क्रोल नहीं करता.

इन इस्तेमाल के उदाहरणों के लिए, TransformingLazyColumn आपको reverseLayout = true सेट करके लेआउट को उलटने की सुविधा देता है. इससे सूची का ऐंकर, सबसे ऊपर वाले किनारे से बदलकर सबसे नीचे वाला किनारा हो जाता है.

आसानी के लिए, reverseLayout = true को सेट करने पर, आइटम का विज़ुअल क्रम और स्क्रोल करने के जेस्चर की दिशा भी उलट जाती है:

  • आइटम को नीचे से ऊपर की ओर व्यवस्थित किया जाता है. इसका मतलब है कि इंडेक्स 0, स्क्रीन पर सबसे नीचे दिखता है.
  • ऊपर की ओर स्क्रोल करने पर, ज़्यादा इंडेक्स वाले आइटम दिखते हैं.

स्नैप-एंड-फ़्लिंग के साथ-साथ रिवर्स लेआउट जोड़ने के लिए, flingBehavior और rotaryScrollableBehavior को एक साथ इस्तेमाल किया जा सकता है. जैसा कि यहां दिए गए स्निपेट में दिखाया गया है:

val columnState = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
ScreenScaffold(scrollState = columnState) { contentPadding ->
    TransformingLazyColumn(
        state = columnState,
        contentPadding = contentPadding,
        reverseLayout = true,
        modifier = Modifier.fillMaxWidth()
    ) {
        items(10) { index ->
            Button(
                label = {
                    Text(
                        text = "Item ${index + 1}"
                    )
                },
                onClick = {},
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding),
                transformation = SurfaceTransformation(transformationSpec)
            )
        }
        item {
            // With reverseLayout = true, the last item declared appears at the top.
            ListHeader(
                modifier = Modifier
                    .fillMaxWidth()
                    .transformedHeight(this, transformationSpec)
                    .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding),
                transformation = SurfaceTransformation(transformationSpec)
            ) {
                Text("Header")
            }
        }
    }
}

यहां दी गई इमेज में, सामान्य सूची और उल्टी सूची के बीच का अंतर दिखाया गया है:

सामान्य लेआउट वाला TransformingLazyColumn, जिसमें आइटम 1 सबसे ऊपर दिख रहा है और आइटम बढ़ते क्रम में दिख रहे हैं.
पहली इमेज. यह एक स्टैंडर्ड लिस्ट लेआउट है, जिसमें कॉन्टेंट ऊपर से नीचे तक दिखता है.
रिवर्स लेआउट वाला TransformingLazyColumn, जिसमें आइटम 1 सबसे नीचे और बाकी आइटम ऊपर की ओर घटते क्रम में दिख रहे हैं.
दूसरी इमेज. यह सूची के लेआउट का उल्टा वर्शन है. इसमें कॉन्टेंट नीचे से ऊपर की ओर दिखता है.

सूचियों पर मौजूद किनारे वाले बटन

Material 3 के लिए, EdgeButton जोड़ा जा सकता है. यह सूची के सबसे नीचे मौजूद, किनारे से जुड़ा बटन होता है. हालांकि, ध्यान रखें कि इसे TransformingLazyColumn में आइटम के तौर पर न जोड़ें. इसके बजाय, ScreenScaffold में edgeButton स्लॉट का इस्तेमाल करें.

edgeButton स्लॉट का इस्तेमाल करने से यह पक्का होता है कि बटन, स्क्रीन पर सबसे नीचे सही जगह पर मौजूद है. साथ ही, सूची को स्क्रोल करने पर यह सही तरीके से काम करता है.

नीचे दिए गए कोड स्निपेट में, EdgeButton को लागू करने का तरीका बताया गया है:

val columnState = rememberTransformingLazyColumnState()
ScreenScaffold(
    scrollState = columnState,
    edgeButton = {
        EdgeButton(
            onClick = { /* TODO */ },
            modifier = Modifier.scrollable(
                columnState,
                orientation = Orientation.Vertical,
                reverseDirection = true,
                // Apply overscroll to the EdgeButton for proper scrolling behavior.
                overscrollEffect = rememberOverscrollEffect(),
            )
        ) {
            Text("More")
        }
    }
) { contentPadding ->
    TransformingLazyColumn(
        contentPadding = contentPadding,
        state = columnState,
    ) {
        // ...
        // ...
    }
}

SwipeToReveal in Lists

SwipeToReveal कॉम्पोनेंट की मदद से, स्वाइप करके सूची में मौजूद किसी आइटम के लिए कार्रवाइयां ऐक्सेस की जा सकती हैं. जैसे, Card या Chip. आम तौर पर, स्वाइप करने पर किनारे से एक या दो ऐक्शन बटन दिखते हैं. जैसे, "मिटाएं" या "ज़्यादा".

TransformingLazyColumn में SwipeToReveal का इस्तेमाल करते समय, इन दिशा-निर्देशों का पालन करें:

  • स्क्रोल करने पर रीसेट करें: जब उपयोगकर्ता सूची को स्क्रोल करता है, तो स्वाइप करके खोले गए सभी आइटम को उनकी मूल स्थिति में रीसेट करें.
  • ऊंचाई एक जैसी होना: ऐक्शन बटन की ऊंचाई को स्वाइप किए गए आइटम (चाहे वह Button हो या Card) की ऊंचाई के बराबर सेट करें, ताकि एक जैसा लुक दिखे.
  • कंटेनर को ट्रांसफ़ॉर्म करना: SwipeToReveal कॉम्पोनेंट पर transformedHeight मॉडिफ़ायर और transformationSpec लागू करें.
  • दो बार ट्रांसफ़ॉर्म न करें: स्वाइप किए गए अंदरूनी आइटम (SwipeToReveal कंटेनर के अंदर मौजूद कार्ड या बटन) पर transformedHeight या transformation मॉडिफ़ायर लागू न करें.