چیدمان حالت رومیزی با Grid و mediaQuery

نماد رده‌بندی ۴ ستاره

وضعیت رومیزی در دستگاه‌های تاشو یک صفحه‌نمایش را به دو ناحیه نمایشگر کاربردی تقسیم می‌کند که با تا شدن فیزیکی (یا لولا) از هم جدا می‌شوند. وضعیت رومیزی به شما امکان می‌دهد محتوای اصلی برنامه‌تان (مانند پخش‌کننده ویدیو یا بوم بازی) را در نیمه بالایی قرار دهید، درحالی‌که عناصر تعاملی (مانند کنترل‌های رسانه یا پدهای کنترل) را در نیمه پایینی قرار می‌دهید.

دستگاه تاشو در حالت رومیزی که محتوای ویدیویی را در صفحه بالا و کنترل‌های بازپخش را در صفحه پایین نشان می‌دهد.
شکل ۱. وضعیت رومیزی محتوا و کنترل‌های تعاملی را در دو طرف خط تای فیزیکی تقسیم می‌کند.

روال‌های مطلوب

برای افزودن پشتیبانی از حالت رومیزی به برنامه‌تان، از میانای برنامه‌سازی کاربردی Grid برای تعریف چیدمانی با دو ردیف و یک ستون استفاده کنید و پُرسمان رسانه‌ای وضعیت پنجره رومیزی را اعمال کنید.

  • شناسایی حالت رومیزی به‌صورت واکنشی: از ترکیب‌پذیر mediaQuery برای مشاهده وضعیت دستگاه استفاده کنید. وقتی دستگاه در وضعیت رومیزی (windowPosture == Posture.Tabletop) تا می‌شود، چیدمان را به‌طور پویا تغییر دهید بدون اینکه نیاز به بازراه‌اندازی فعالیت یا مدیریت پیچیده چرخه حیات باشد.
  • ساختاربندی چیدمان‌ها با Grid: وقتی دستگاه در وضعیت رومیزی است، از Grid API‏ (2 rows، 1 column) استفاده کنید تا محتوای دیداری اصلی را به‌طور تمیز در ردیف بالا بالای خط تا و کنترل‌های تعاملی را در ردیف پایین زیر خط تا جدا کنید.
  • استفاده از نمایه‌سازی z ضمنی برای هم‌پوشانی‌ها: در حالت‌های استاندارد (غیررومیزی)، چندین شناسه ناحیه را به یک سلول اختصاص دهید تا کنترل‌ها روی پخش‌کننده هم‌پوشانی شوند. Grid به‌طور خودکار موارد را به‌ترتیب اعلامشان از پشت به جلو ارائه می‌کند.
  • ارائه انتقال‌های روان: مطمئن شوید که وضعیت و موقعیت‌های پیمایش هنگام انتقال بین چیدمان‌های تمام‌صفحه استاندارد و حالت افقی روبه‌صورت حفظ می‌شوند.

مواد تشکیل‌دهنده

  • Grid: محفظه چیدمان تطبیقی که به شما امکان می‌دهد موارد را در ردیف‌ها و ستون‌های قابل‌پیکربندی قرار دهید، ایده‌آل برای تقسیم محتوا در مناطق مختلف صفحه‌نمایش.
  • mediaQuery: یک Jetpack Compose API که برای پُرسمان مستقیم وضعیت فعلی پنجره برنامه، کلاس‌های اندازه، و ویژگی‌های سخت‌افزاری در composable شما استفاده می‌شود.

قدم‌ها

بااستفاده از mediaQuery()، وضعیت دستگاه را پرسمان کنید. وقتی دستگاه در وضعیت افقی روبه‌صورت است، محتوای برنامه‌تان را در جدولی عمودی با دو ردیف و یک ستون مرتب کنید و مطمئن شوید محتوای اصلی در بالا قرار می‌گیرد و کنترل‌ها در پایین قابل‌دسترس هستند.

۱. پیکربندی‌های Grid را برای حالت رومیزی تعریف کنید

درون یک تابع ترکیب‌پذیر، شناسه‌های ناحیه چیدمان را بااستفاده از یک enum تعریف کنید و بلوک‌های GridConfigurationScope را برای حالت‌های پیش‌فرض و رومیزی تنظیم کنید.

در defaultConfig، هر دو ناحیه به یک سلول (row = 1, column = 1) اختصاص داده شده‌اند. Grid از نمایه‌سازی z ضمنی استفاده می‌کند که در آن، ترکیب‌پذیرهایی که بعداً در چیدمان اعلام می‌شوند، روی ترکیب‌پذیرهای قبلی ارائه می‌شوند و به کنترل‌کننده اجازه می‌دهند بدون تودرتو کردن ظرف اضافی، روی پخش‌کننده قرار گیرد (برای جزئیات بیشتر، به هم‌پوشانی‌های عنصر میانای کاربر با Grid مراجعه کنید).

enum class VideoPlayerArea { Player, Controller }

object PlayerGridConfig {
    // Default: Single area layout with overlay (controls on top of player)
    val defaultConfig: GridConfigurationScope.() -> Unit = {
        row(1f)
        column(1f)
        area(areaId = VideoPlayerArea.Player, row = 1, column = 1)
        area(areaId = VideoPlayerArea.Controller, row = 1, column = 1)
    }

    // Tabletop: Two rows splitting content across the fold
    val tabletopConfig: GridConfigurationScope.() -> Unit = {
        row(0.5f)
        row(0.5f)
        column(1f)
        area(areaId = VideoPlayerArea.Player, row = 1, column = 1) // Top half above fold
        area(areaId = VideoPlayerArea.Controller, row = 2, column = 1) // Bottom half below fold
    }
}

۲. تشخیص حالت رومیزی و اعمال پیکربندی در Grid

از mediaQuery برای انتخاب پیکربندی فعال براساس windowPosture استفاده کنید، config را به Grid ارسال کنید، و محتوای قابل‌ترکیب را به شناسه‌های ناحیه مقید کنید. اعلام VideoPlayerArea.Player قبل‌از VideoPlayerArea.Controller تضمین می‌کند که وقتی هر دو یک سلول را در defaultConfig هم‌رسانی می‌کنند، کنترل‌ها بالای پخش‌کننده ارائه می‌شوند:

val config = mediaQuery {
    when (windowPosture) {
        Posture.Tabletop -> PlayerGridConfig.tabletopConfig
        else -> PlayerGridConfig.defaultConfig
    }
}

Grid(config = config) {
    Box(
        modifier = Modifier
            .gridItem(areaId = VideoPlayerArea.Player)
    ) {
        // VideoPlayerContent
    }

    Box(
        modifier = Modifier
            .gridItem(areaId = VideoPlayerArea.Controller)
    ) {
        // PlaybackControlsContent
    }
}

نتایج

با ترکیب mediaQuery و Grid، برنامه شما به‌طور پویا تشخیص می‌دهد که دستگاه تاشو تاحدی در وضعیت افقی روبه‌صورت تا شده است و به‌طور خودکار واسط کاربر خود را به دو ناحیه نمایشگر کاربردی تقسیم‌شده با خط تا تنظیم می‌کند.

منابع بیشتر