Wear OS-এর জন্য Compose-এ আপনার UI প্রিভিউ করুন

অ্যান্ড্রয়েড স্টুডিও কম্পোজ প্রিভিউ আপনাকে কোনো ফিজিক্যাল ঘড়ি বা এমুলেটরে আপনার অ্যাপ ডেপ্লয় না করেই, সরাসরি IDE-এর মধ্যে বিভিন্ন ঘড়ির ডিসপ্লে সাইজ, গোলাকার বেজেল এবং ফন্ট স্কেলে আপনার Wear OS কম্পোজেবলগুলো পরিদর্শন ও যাচাই করার সুযোগ দেয়।

যেহেতু Wear OS ডিভাইসগুলোর ডিসপ্লে গোলাকার হওয়ায় এর কোণাগুলো কন্টেন্টকে কেটে দেয় এবং TimeText ও ScrollIndicator মতো সিস্টেম ওভারলেগুলো স্ক্রিনের কিনারা বরাবর বাঁকানো থাকে, তাই লেআউটের সমস্যাগুলো আগেভাগে ধরার জন্য বিশেষভাবে Wear OS-এর জন্য প্রিভিউ কনফিগার করা অপরিহার্য।


প্রিভিউ নির্ভরতা সেট আপ করুন

Wear OS Compose প্রিভিউ অ্যানোটেশন এবং ডিভাইস ডেফিনিশন ব্যবহার করতে, আপনার মডিউলের build.gradle.kts ফাইলে নিম্নলিখিত ডিপেন্ডেন্সিগুলো যোগ করুন:

dependencies {
    // Provides @WearPreview* multipreview annotations
    // (such as @WearPreviewDevices and @WearPreviewFontScales)
    implementation("androidx.wear.compose:compose-ui-tooling:1.7.0")

    // Provides WearDevices constants
    // (such as WearDevices.SMALL_ROUND and WearDevices.LARGE_ROUND)
    implementation("androidx.wear:wear-tooling-preview:1.0.0")

    // Standard Compose preview support and interactive/animation inspection
    implementation("androidx.compose.ui:ui-tooling-preview")
    debugImplementation("androidx.compose.ui:ui-tooling")
}

কী প্রিভিউ করবেন তা বেছে নিন: স্ক্রিন বনাম কম্পোনেন্ট

আপনি পুরো স্ক্রিন নাকি কোনো বিচ্ছিন্ন UI কম্পোনেন্ট প্রিভিউ করছেন, তার ওপর নির্ভর করে প্রিভিউটি কীভাবে কনফিগার করবেন।

পূর্ণ স্ক্রিন প্রিভিউ করুন ( AppScaffold + ScreenScaffold )

সম্পূর্ণ স্ক্রিন প্রিভিউ করার সময়, একটি Wear ডিভাইস প্রিভিউ অ্যানোটেশন ব্যবহার করে আপনার স্ক্রিন কম্পোজেবলকে সর্বদা AppScaffold এবং ScreenScaffold উভয়ের মধ্যে র‍্যাপ করুন। এটি বৃত্তাকার ঘড়ির ডিসপ্লে রেন্ডার করে এবং নিশ্চিত করে যে:

  • TimeText ঘড়ির ডিসপ্লের উপরের বাঁকানো প্রান্তে প্রদর্শিত হয়।
  • ScrollIndicator ডান বেজেল বরাবর প্রদর্শিত হয়।
  • EdgeButton নিচের বাঁকে সঠিকভাবে অবস্থান করছে এবং ক্লিপ করা আছে।
  • কন্টেন্ট প্যাডিং এবং বৃত্তাকার স্ক্রিন ক্লিপিং আসল ঘড়ির হার্ডওয়্যারকে নির্ভুলভাবে প্রতিফলিত করে।
@WearPreviewDevices
@Composable
fun WorkoutScreenPreview() {
    MaterialTheme {
        // AppScaffold provides the top-level TimeText overlay
        AppScaffold {
            // WorkoutScreen contains its own ScreenScaffold and content
            WorkoutScreen(
                heartRate = 142,
                elapsedTime = "12:45"
            )
        }
    }
}
WearDevices.SMALL_ROUND-এ WorkoutScreenPreview রেন্ডার করা হয়েছে।

ছোট গোলাকার (১৯২x১৯২ডিপি)

WearDevices.LARGE_ROUND-এ WorkoutScreenPreview রেন্ডার করা হয়েছে।

বড় গোলাকার (২২৭x২২৭ডিপি)

বিচ্ছিন্ন উপাদানগুলির পূর্বরূপ দেখুন

কাস্টম Card , Button বা স্ট্যাটাস চিপের মতো স্বতন্ত্র কম্পোনেন্ট প্রিভিউ করার সময়, device প্যারামিটারটি বাদ দিন এবং একটি ডার্ক ব্যাকগ্রাউন্ড সহ স্ট্যান্ডার্ড @Preview ব্যবহার করুন। এটি নিশ্চিত করে যে একটি সম্পূর্ণ বৃত্তাকার ওয়াচ ডিসপ্লে রেন্ডার না করেই Wear Material 3-এর রঙ এবং কনট্রাস্ট সঠিকভাবে প্রদর্শিত হয়।

@Preview(
    showBackground = true,
    backgroundColor = 0xFF000000
)
@Composable
fun HeartRateCardPreview() {
    MaterialTheme {
        HeartRateCard(bpm = 142, zone = "Aerobic")
    }
}
ওয়াচ ফ্রেম ছাড়া HeartRateCardPreview বিচ্ছিন্ন কম্পোনেন্টের প্রিভিউ

বিচ্ছিন্ন কম্পোনেন্ট প্রিভিউ (কোন ডিভাইস ফ্রেম নেই)।


অন্তর্নির্মিত মাল্টিপ্রিভিউ টীকা

androidx.wear.compose.ui.tooling.preview প্যাকেজটিতে বিল্ট-ইন অ্যানোটেশন রয়েছে যা স্বয়ংক্রিয়ভাবে ডার্ক ব্যাকগ্রাউন্ড ( backgroundColor = 0xFF000000 , showBackground = true ) এবং ওয়াচ ডিভাইসের বৃত্তাকার ডাইমেনশন কনফিগার করে:

টীকা এটি যা রেন্ডার করে কখন ব্যবহার করবেন
@WearPreviewSmallRound WearDevices.SMALL_ROUND (192x192dp)-এ ১টি প্রিভিউ। সবচেয়ে সীমাবদ্ধ বৃত্তাকার প্রদর্শনের আকারের উপর দ্রুত পুনরাবৃত্তি।
@WearPreviewLargeRound WearDevices.LARGE_ROUND (227x227dp)-এ ১টি প্রিভিউ। বড় ঘড়িগুলিতে লেআউটের ঘনত্ব এবং অতিরিক্ত ফাঁকা স্থান পরীক্ষা করা হচ্ছে।
@WearPreviewDevices ২টি প্রিভিউ : SMALL_ROUND এবং LARGE_ROUND । প্রতিটি কম্পোজেবল স্ক্রিনের জন্য স্ট্যান্ডার্ড মাল্টিডিভাইস চেক।
@WearPreviewFontScales Wear ফন্টের সকল স্কেলে SMALL_ROUND এর ৬টি প্রিভিউ : Small ( 0.94f ), Normal ( 1.0f ), Medium ( 1.06f ), Large ( 1.12f ), Larger ( 1.18f ), এবং Largest ( 1.24f )। টেক্সট র‍্যাপিং, সংক্ষিপ্তকরণ এবং বাটনের উচ্চতা প্রসারণ পরীক্ষা করা হচ্ছে।

একটি ব্যাপক টেস্ট ম্যাট্রিক্স তৈরি করতে আপনি একই প্রিভিউ ফাংশনে @WearPreviewDevices এবং @WearPreviewFontScales একসাথে ব্যবহার করতে পারেন:

@WearPreviewDevices
@WearPreviewFontScales
@Composable
fun MessageDetailScreenPreview() {
    MaterialTheme {
        AppScaffold {
            MessageDetailScreen(
                sender = "Alex",
                body = "Running 5 mins late!"
            )
        }
    }
}

কাস্টম প্রিভিউ টীকা এবং হার্ডওয়্যার স্পেসিফিকেশন

যখন আপনার আরও সূক্ষ্ম নিয়ন্ত্রণের প্রয়োজন হয়—যেমন নির্দিষ্ট হার্ডওয়্যারের মাত্রা, দীর্ঘ স্থানীয় স্ট্রিং বা সবচেয়ে খারাপ পরিস্থিতিগুলোর সমন্বয় পরীক্ষা করার জন্য—তখন আপনি সরাসরি @Preview কনফিগার করতে পারেন অথবা আপনার নিজস্ব কাস্টম মাল্টিপ্রিভিউ অ্যানোটেশন সংজ্ঞায়িত করতে পারেন।

উপলব্ধ WearDevices ধ্রুবক এবং কাস্টম হার্ডওয়্যার স্পেসিফিকেশন

androidx.wear.tooling.preview.devices.WearDevices অবজেক্টটি স্ট্যান্ডার্ড ডিভাইস আইডি প্রদান করে:

  • WearDevices.SMALL_ROUND ( "id:wearos_small_round" , 192x192dp)
  • WearDevices.LARGE_ROUND ( "id:wearos_large_round" , 227x227dp)

অতিরিক্ত বড় গোলাকার ডিসপ্লেতে (যেমন ৪৪মিমি–৪৫মিমি ঘড়ি বা ২৪০x২৪০ডিপি রেজোলিউশনের আল্ট্রা মডেল) প্রিভিউ করার জন্য, device প্যারামিটারে একটি কাস্টম spec: স্ট্রিং পাস করুন:

@Preview(
    name = "XL Round Watch (240dp)",
    device = "spec:width=240dp,height=240dp,dpi=320,isRound=true",
    showBackground = true,
    backgroundColor = 0xFF000000
)
@Composable
fun WorkoutScreenXlPreview() {
    MaterialTheme {
        AppScaffold {
            WorkoutScreen(heartRate = 142, elapsedTime = "12:45")
        }
    }
}

একটি কাস্টম মাল্টি-প্রিভিউ অ্যানোটেশন তৈরি করুন

একটি চরম পরিস্থিতি পরীক্ষা করার জন্য, একটি কাস্টম মাল্টি-প্রিভিউ অ্যানোটেশন তৈরি করুন যা একটি সাধারণ বড় গোলাকার স্ক্রিনের পাশাপাশি সবচেয়ে ছোট গোলাকার স্ক্রিন , সবচেয়ে বড় ফন্ট স্কেল এবং একটি বিশদ লোকেল (যেমন জার্মান) যুক্ত করে:

@Preview(
    name = "1. Standard Large Round",
    group = "Layout extremes",
    device = WearDevices.LARGE_ROUND,
    backgroundColor = 0xFF000000,
    showBackground = true
)
@Preview(
    name = "2. Extreme Small Round (Largest Font + German)",
    group = "Layout extremes",
    device = WearDevices.SMALL_ROUND,
    fontScale = 1.24f,
    locale = "de-rDE",
    backgroundColor = 0xFF000000,
    showBackground = true
)
annotation class WearPreviewExtremes
স্ট্যান্ডার্ড বড় গোলাকার প্রিভিউ

১. স্ট্যান্ডার্ড বড় গোলাকার

সবচেয়ে বড় ফন্ট স্কেল সহ অত্যন্ত ছোট গোলাকার

২. অত্যন্ত ছোট গোলাকার (বৃহত্তম ফন্ট + জার্মান)


স্ক্রোলিং কলামের প্রিভিউ দেখুন ( TransformingLazyColumn )

ডিফল্টরূপে, একটি TransformingLazyColumn তার প্রথম আইটেমটি ( index = 0 ) স্ক্রিনের শীর্ষে পিন করা অবস্থায় ইনিশিয়ালাইজ হয়। তবে, Wear OS-এ, আইটেমগুলো স্ক্রিনের ওপর ও নিচের বাঁকানো প্রান্তের কাছাকাছি আসার সাথে সাথে তাদের উচ্চতা এবং গোলাকার কোণাগুলো ( SurfaceTransformation ) পরিবর্তিত হয়, এবং EdgeButton টি কেবল স্ক্রল করে একেবারে নিচে গেলেই দেখা যায়।

আপনার তালিকাটি আংশিকভাবে স্ক্রল করলে বা তালিকার একেবারে নিচে থাকলে কেমন দেখাবে তা প্রিভিউ করতে:

ধাপ ১: আপনার স্ক্রিন কম্পোজেবলে TransformingLazyColumnState হোইস্ট করুন।

আপনার স্ক্রিন কম্পোজেবলকে একটি TransformingLazyColumnState প্যারামিটার গ্রহণ করার অনুমতি দিন, যার ডিফল্ট মান হবে rememberTransformingLazyColumnState() :

@Composable
fun InboxScreen(
    messages: List<Message>,
    columnState: TransformingLazyColumnState = rememberTransformingLazyColumnState(),
) {
    val transformationSpec = rememberTransformationSpec()

    ScreenScaffold(
        scrollState = columnState,
        edgeButton = {
            EdgeButton(onClick = { /* Compose new */ }) {
                Text("New message")
            }
        }
    ) { contentPadding ->
        TransformingLazyColumn(
            state = columnState,
            contentPadding = contentPadding,
        ) {
            items(messages.size) { index ->
                Card(
                    onClick = {},
                    modifier = Modifier
                        .fillMaxWidth()
                        .transformedHeight(this, transformationSpec)
                        .minimumVerticalContentPadding(
                            CardDefaults.minimumVerticalListContentPadding
                        ),
                    transformation = SurfaceTransformation(transformationSpec),
                ) {
                    Text(messages[index].subject)
                }
            }
        }
    }
}

ধাপ ২: আপনার @Preview তে initialAnchorItemIndex পাস করুন।

rememberTransformingLazyColumnState দুটি ঐচ্ছিক প্রাথমিক স্ক্রোল প্যারামিটার গ্রহণ করে:

  • initialAnchorItemIndex: Int : যখন এটিকে একটি অ-ঋণাত্মক সূচকে (উদাহরণস্বরূপ, 3 ) সেট করা হয়, তখন তালিকাটি সেই আইটেমটিকে ওয়াচ ভিউপোর্টের কেন্দ্রে রেখে শুরু হয়।
  • initialAnchorItemScrollOffset: Int : কেন্দ্রস্থ অ্যাঙ্কর আইটেমের সাপেক্ষে প্রয়োগ করা ঐচ্ছিক পিক্সেল অফসেট।

আপনি একই স্ক্রিনের টপ , মিডল (স্ক্রোল করা) এবং বটম ( EdgeButton দৃশ্যমান) অবস্থা পাশাপাশি প্রিভিউতে দেখাতে পারেন:

@WearPreviewLargeRound
@Composable
fun InboxScreenTopPreview() {
    MaterialTheme {
        AppScaffold {
            // Default (-1): Pinned to top of list (index 0)
            InboxScreen(messages = sampleMessages)
        }
    }
}

@WearPreviewLargeRound
@Composable
fun InboxScreenScrolledMiddlePreview() {
    MaterialTheme {
        AppScaffold {
            // Centers item index 3 in the viewport, showing top/bottom item morphing
            InboxScreen(
                messages = sampleMessages,
                columnState = rememberTransformingLazyColumnState(
                    initialAnchorItemIndex = 3
                )
            )
        }
    }
}

@WearPreviewLargeRound
@Composable
fun InboxScreenBottomEdgeButtonPreview() {
    MaterialTheme {
        AppScaffold {
            // Anchors on the last item so the EdgeButton is visible at the bottom
            InboxScreen(
                messages = sampleMessages,
                columnState = rememberTransformingLazyColumnState(
                    initialAnchorItemIndex = sampleMessages.lastIndex
                )
            )
        }
    }
}
ইনবক্সস্ক্রিন তালিকার শীর্ষে পিন করা আছে

শীর্ষ (ডিফল্ট -1 )

ইনবক্সস্ক্রিনটি মাঝের সূচক ৩-এ স্ক্রোল করা হয়েছে

মধ্যবর্তী ( initialAnchorItemIndex = 3 )

এজ বাটন প্রসারিত অবস্থায় ইনবক্স স্ক্রিনটি একেবারে নিচে স্ক্রল করা হয়েছে।

নীচে ( EdgeButton প্রসারিত)

টিপস: আপনি অ্যান্ড্রয়েড স্টুডিও-তে যেকোনো @Preview তে ‘স্টার্ট ইন্টারেক্টিভ মোড’ ক্লিক করে আপনার মাউস বা ট্র্যাকপ্যাড দিয়ে TransformingLazyColumn লাইভ স্ক্রল করতে পারেন এবং রিয়েল টাইমে SurfaceTransformation মর্ফিং, EdgeButton এন্ট্রান্স অ্যানিমেশন এবং ScrollIndicator মুভমেন্ট পর্যবেক্ষণ করতে পারেন।

স্ক্রোল ক্যাপচারের সময় ScrollIndicator সুরক্ষিত রাখুন ( LocalScrollCaptureInProgress )

যখন সিস্টেম স্ক্রল ক্যাপচার (দীর্ঘ স্ক্রিনশট) বা মাল্টি-ফ্রেম স্ক্রিনশট টেস্টিং টুল একটি স্ক্রলিং TransformingLazyColumn ক্যাপচার করে, তখন Compose একাধিক ভিউপোর্ট টাইলকে উল্লম্বভাবে ক্যাপচার ও স্টিচিং করার সময় LocalScrollCaptureInProgress.current কে true সেট করে।

যেহেতু ScreenScaffold স্ক্রল ক্যাপচারের সময় তার scrollIndicator স্বয়ংক্রিয়ভাবে লুকায় না, তাই একটি দীর্ঘ স্ক্রিনশটের প্রতিটি জোড়া লাগানো টাইলে ভাসমান স্ক্রলবার ওভারলেটি বারবার প্রদর্শিত হবে, যদি না আপনি !LocalScrollCaptureInProgress.current ব্যবহার করে এটিকে স্পষ্টভাবে সুরক্ষিত করেন।

ScreenScaffold(
    scrollState = columnState,
    scrollIndicator = {
        if (!LocalScrollCaptureInProgress.current) {
            ScrollIndicator(state = columnState)
        }
    }
) { contentPadding ->
    // TransformingLazyColumn content...
    // ...
}