جستجوی اطلاعات برای طرح‌بندی‌های تطبیقی ​​با mediaQuery

برای به‌روزرسانی طرح‌بندی برنامه خود، به انواع مختلفی از اطلاعات، مانند قابلیت دستگاه و وضعیت برنامه، نیاز دارید. عرض و ارتفاع پنجره رایج‌ترین اطلاعات مورد استفاده هستند. علاوه بر آن، می‌توانید به اطلاعات زیر نیز مراجعه کنید:

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

از آنجا که اطلاعات به صورت پویا به‌روزرسانی می‌شوند، باید آن را رصد کنید و در صورت وقوع هرگونه به‌روزرسانی، ترکیب‌بندی مجدد را فعال کنید. تابع mediaQuery جزئیات بازیابی اطلاعات را خلاصه می‌کند و به شما امکان می‌دهد تا روی تعریف شرط لازم برای راه‌اندازی به‌روزرسانی‌های طرح‌بندی تمرکز کنید. مثال زیر، طرح‌بندی را هنگامی که حالت تاشو روی میز است، به TabletopLayout تغییر می‌دهد:

@Composable
fun VideoPlayer(
    // ...
) {
    // ...
            if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
                TabletopLayout()
            } else {
                FlatLayout()
            }
    // ...
}

تابع mediaQuery را فعال کنید

برای فعال کردن تابع mediaQuery ، ویژگی isMediaQueryIntegrationEnabled از شیء ComposeUiFlags را روی true تنظیم کنید:

class MyApplication : Application() {
    override fun onCreate() {
        ComposeUiFlags.isMediaQueryIntegrationEnabled = true
        super.onCreate()
    }
}

تعریف شرط با پارامترها

شما می‌توانید یک شرط را به عنوان یک لامبدا تعریف کنید که درون UiMediaScope ارزیابی می‌شود. تابع mediaQuery شرط را بر اساس وضعیت فعلی و قابلیت‌های دستگاه ارزیابی می‌کند. این تابع یک مقدار بولی برمی‌گرداند، بنابراین می‌توانید طرح‌بندی را با شاخه‌های شرطی مانند یک عبارت if تعیین کنید. جدول 1 پارامترهای موجود در UiMediaScope را شرح می‌دهد.

پارامتر نوع مقدار توضیحات
windowWidth Dp عرض پنجره فعلی بر حسب dp.
windowHeight Dp ارتفاع فعلی پنجره بر حسب dp.
windowPosture UiMediaScope.Posture وضعیت فعلی پنجره برنامه.
pointerPrecision UiMediaScope.PointerPrecision بالاترین دقت در بین دستگاه‌های نشانه‌روی موجود.
keyboardKind UiMediaScope.KeyboardKind نوع صفحه کلید موجود یا متصل.
hasCamera Boolean اینکه آیا دوربین روی دستگاه پشتیبانی می‌شود یا خیر.
hasMicrophone Boolean اینکه آیا میکروفون در دستگاه پشتیبانی می‌شود یا خیر.
viewingDistance UiMediaScope.ViewingDistance فاصله معمول بین کاربر و صفحه نمایش دستگاه.

یک شیء UiMediaScope مقادیر پارامترها را تعیین می‌کند. تابع mediaQuery از LocalUiMediaScope.current برای دسترسی به شیء UiMediaScope استفاده می‌کند که نشان‌دهنده قابلیت‌ها و زمینه فعلی دستگاه است. این شیء به صورت پویا با ایجاد هرگونه تغییر، مانند زمانی که کاربر وضعیت دستگاه را تغییر می‌دهد، به‌روزرسانی می‌شود. سپس تابع mediaQuery ، لامبدا query را با شیء UiMediaScope به‌روزرسانی‌شده ارزیابی کرده و یک مقدار بولی برمی‌گرداند. به عنوان مثال، قطعه کد زیر بر اساس مقدار پارامتر windowPosture بین TabletopLayout و FlatLayout یکی را انتخاب می‌کند.

@Composable
fun VideoPlayer(
    // ...
) {
    // ...
            if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
                TabletopLayout()
            } else {
                FlatLayout()
            }
    // ...
}

بر اساس اندازه پنجره تصمیم بگیرید

کلاس‌های اندازه پنجره مجموعه‌ای از نقاط توقف دیدگاه‌های مختلف هستند که به شما در طراحی، توسعه و آزمایش طرح‌بندی‌های تطبیقی ​​کمک می‌کنند. می‌توانید دو پارامتر نشان دهنده اندازه فعلی پنجره را با آستانه تعریف شده در کلاس‌های اندازه پنجره مقایسه کنید. مثال زیر تعداد پنل‌ها را با توجه به عرض پنجره تغییر می‌دهد. کلاس WindowSizeClass دارای ثابت‌هایی برای آستانه‌های کلاس‌های اندازه پنجره است (شکل 1).

تابع derivedMediaQuery لامبدا query را ارزیابی کرده و نتیجه را در یک derivedStateOf قرار می‌دهد. از آنجایی که windowWidth و windowHeight می‌توانند مرتباً به‌روزرسانی شوند، هنگام ارجاع به این پارامترها در لامبدا query ، به جای تابع mediaQuery تابع derivedMediaQuery را فراخوانی کنید.

val narrowerThanMedium by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND.dp
}
val narrowerThanExpanded by derivedMediaQuery {
    windowWidth < WindowSizeClass.WIDTH_DP_EXPANDED_LOWER_BOUND.dp
}
when {
    narrowerThanMedium -> SinglePaneLayout()
    narrowerThanExpanded -> TwoPaneLayout()
    else -> ThreePaneLayout()
}

شکل ۱. طرح‌بندی بر اساس عرض پنجره به‌روزرسانی می‌شود.

طرح‌بندی را با توجه به موقعیت پنجره به‌روزرسانی کنید

پارامتر windowPosture وضعیت فعلی پنجره را به عنوان یک شیء UiMediaScope.Posture توصیف می‌کند. می‌توانید وضعیت فعلی را با مقایسه پارامتر با مقادیر تعریف شده در کلاس UiMediaScope.Posture بررسی کنید. مثال زیر طرح‌بندی را بر اساس وضعیت پنجره تغییر می‌دهد:

when {
    mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}

دقت دستگاه نشانه‌روی موجود را بررسی کنید

یک دستگاه اشاره‌گر با دقت بالا به کاربران کمک می‌کند تا به طور دقیق به یک عنصر رابط کاربری اشاره کنند. دقت یک دستگاه اشاره‌گر به نوع دستگاه بستگی دارد.

پارامتر pointerPrecision دقت دستگاه‌های اشاره‌گر موجود، مانند ماوس و صفحه لمسی را توصیف می‌کند. چهار مقدار در کلاس UiMediaScope.PointerPrecision تعریف شده است: Fine ، Coarse ، Blunt و None . None به این معنی است که هیچ دستگاه اشاره‌گری در دسترس نیست. دقت از بالاترین به پایین‌ترین به این ترتیب متغیر است: Fine ، Coarse و Blunt .

اگر چندین دستگاه اشاره‌گر در دسترس باشند و دقت آنها متفاوت باشد، پارامتر با بالاترین آن حل می‌شود. برای مثال، اگر دو دستگاه اشاره‌گر وجود داشته باشد - یک دستگاه با دقت Fine و یک دستگاه با دقت Blunt - Fine مقدار پارامتر pointerPrecision است.

مثال زیر، دکمه‌ای بزرگتر را نشان می‌دهد وقتی کاربر از یک دستگاه اشاره‌گر با دقت پایین استفاده می‌کند:

if (mediaQuery { pointerPrecision == UiMediaScope.PointerPrecision.Blunt }) {
    LargeSizeButton()
} else {
    NormalSizeButton()
}

نوع صفحه کلید موجود را بررسی کنید

پارامتر keyboardKind نوع کیبوردهای موجود را نشان می‌دهد: Physical ، Virtual و None . اگر یک کیبورد روی صفحه نمایش داده شود و همزمان یک کیبورد سخت‌افزاری نیز در دسترس باشد، پارامتر به صورت Physical در نظر گرفته می‌شود. اگر هیچ‌کدام شناسایی نشوند، مقدار پارامتر None خواهد بود. مثال زیر پیامی را نشان می‌دهد که به کاربران پیشنهاد می‌دهد در صورت عدم شناسایی کیبورد، یک کیبورد را متصل کنند:

if (mediaQuery { keyboardKind == UiMediaScope.KeyboardKind.None }) {
    SuggestKeyboardConnect()
}

بررسی کنید که آیا دستگاه از دوربین و میکروفون پشتیبانی می‌کند یا خیر

برخی از دستگاه‌ها از دوربین یا میکروفون پشتیبانی نمی‌کنند. می‌توانید با استفاده از پارامترهای hasCamera و hasMicrophone بررسی کنید که آیا دستگاه از دوربین و میکروفون پشتیبانی می‌کند یا خیر. مثال زیر دکمه‌هایی را برای استفاده با دوربین و میکروفون در صورت پشتیبانی دستگاه نشان می‌دهد:

Row {
    OutlinedTextField(state = rememberTextFieldState())
    // Show the MicButton when the device supports a microphone.
    if (mediaQuery { hasMicrophone }) {
        MicButton()
    }
    // Show the CameraButton when the device supports a camera.
    if (mediaQuery { hasCamera }) {
        CameraButton()
    }
}

رابط کاربری را با فاصله دید تخمینی تنظیم کنید

فاصله دید عاملی است که به تعیین طرح‌بندی کمک می‌کند. اگر کاربر از فاصله دور از برنامه استفاده کند، انتظار دارد متن و عناصر رابط کاربری بزرگتر باشند. پارامتر viewingDistance تخمینی از فاصله دید را بر اساس نوع دستگاه و زمینه استفاده معمول آن ارائه می‌دهد.

سه مقدار در کلاس UiMediaScope.ViewingDistance تعریف شده است: Near ، Medium و Far . Near به این معنی است که صفحه نمایش در فاصله نزدیک قرار دارد و Far به این معنی است که دستگاه از فاصله دور مشاهده می‌شود. مثال زیر وقتی فاصله مشاهده Far یا Medium باشد، اندازه فونت را افزایش می‌دهد:

val fontSize = when {
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Far } -> 20.sp
    mediaQuery { viewingDistance == UiMediaScope.ViewingDistance.Medium } -> 18.sp
    else -> 16.sp
}

پیش‌نمایش یک کامپوننت رابط کاربری

شما می‌توانید توابع mediaQuery و derivedMediaQuery را در توابع composable برای پیش‌نمایش کامپوننت‌های رابط کاربری فراخوانی کنید. قطعه کد زیر بر اساس مقدار پارامتر windowPosture ، بین TabletopLayout و FlatLayout یکی را انتخاب می‌کند. برای پیش‌نمایش TabletopLayout ، پارامتر windowPosture باید UiMediaScope.Posture.Tabletop باشد.

when {
    mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
    mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
}

توابع mediaQuery و derivedMediaQuery لامبدا query داده شده را درون یک شیء UiMediaScope ارزیابی می‌کنند که به صورت LocalUiMediaScope.current ارائه می‌شود. می‌توانید آن را با مراحل زیر بازنویسی کنید:

  1. تابع mediaQuery را فعال کنید.
  2. یک شیء سفارشی تعریف کنید که رابط UiMediaScope را پیاده‌سازی کند.
  3. شیء سفارشی را با استفاده از تابع CompositionLocalProvider روی LocalUiMediaScope تنظیم کنید.
  4. برای پیش‌نمایش در محتوای لامبدا از تابع CompositionLocalProvider تابع composable را فراخوانی کنید.

شما می‌توانید TabletopLayout با مثال زیر پیش‌نمایش کنید:

@Preview
@Composable
fun PreviewLayoutForTabletop() {
    // Step 1: Enable the mediaQuery function
    ComposeUiFlags.isMediaQueryIntegrationEnabled = true

    val currentUiMediaScope = LocalUiMediaScope.current
    // Step 2: Define a custom object implementing the UiMediaScope interface.
    // The object overrides the windowPosture parameter.
    // The resolution of the remaining parameters is deferred to the currentUiMediaScope object.
    val uiMediaScope = remember(currentUiMediaScope) {
        object : UiMediaScope by currentUiMediaScope {
            override val windowPosture: UiMediaScope.Posture = UiMediaScope.Posture.Tabletop
        }
    }

    // Step 3: Set the object to the LocalUiMediaScope.
    CompositionLocalProvider(LocalUiMediaScope provides uiMediaScope) {
        // Step 4: Call the composable to preview.
        when {
            mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop } -> TabletopLayout()
            mediaQuery { windowPosture == UiMediaScope.Posture.Book } -> BookLayout()
            mediaQuery { windowPosture == UiMediaScope.Posture.Flat } -> FlatLayout()
        }
    }
}