پشتیبانی از اندازه های مختلف صفحه نمایش

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

برای پشتیبانی از اندازه‌های صفحه نمایش تا حد امکان، طرح‌بندی برنامه‌های خود را به گونه‌ای طراحی کنید که پاسخگو و تطبیقی ​​باشند. طرح‌بندی‌های واکنش‌گرا/تطبیقی ​​بدون در نظر گرفتن اندازه صفحه‌نمایش، تجربه کاربری بهینه‌سازی‌شده‌ای را ارائه می‌کنند، و برنامه شما را قادر می‌سازد تا تلفن‌ها، تبلت‌ها، تاشوها، دستگاه‌های ChromeOS، جهت‌های عمودی و افقی و پیکربندی‌های قابل تغییر اندازه مانند حالت چند پنجره‌ای را در خود جای دهد.

طرح بندی پاسخگو/تطبیقی ​​بر اساس فضای نمایش موجود تغییر می کند. تغییرات از تنظیمات طرح‌بندی کوچک که فضا را پر می‌کند (طراحی واکنش‌گرا) تا جایگزینی کامل یک طرح‌بندی با طرح‌بندی دیگر را شامل می‌شود تا برنامه شما بتواند اندازه‌های مختلف نمایشگر را به بهترین شکل در خود جای دهد (طراحی تطبیقی).

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

تغییرات طرح‌بندی بزرگ را برای کامپوزیشن‌های سطح صفحه نمایش آشکار کنید

وقتی از Compose برای چیدمان یک برنامه کامل استفاده می کنید، کامپوزیشن های سطح برنامه و صفحه نمایش، تمام فضایی را که برنامه شما برای نمایش داده شده است، اشغال می کند. در این سطح از طراحی شما، ممکن است منطقی باشد که چیدمان کلی یک صفحه را تغییر دهید تا از مزایای صفحه نمایش بزرگتر استفاده کنید.

از استفاده از مقادیر فیزیکی و سخت افزاری برای تصمیم گیری در مورد چیدمان خودداری کنید. ممکن است تصمیم گیری بر اساس یک مقدار ثابت و ملموس وسوسه انگیز باشد (آیا دستگاه تبلت است؟ آیا صفحه نمایش فیزیکی نسبت ابعاد خاصی دارد؟)، اما پاسخ به این سؤالات ممکن است برای تعیین فضایی که رابط کاربری شما می تواند کار کند مفید نباشد. با

نموداری که چندین فاکتور شکل دستگاه مختلف از جمله تلفن، تاشو، تبلت و لپ‌تاپ را نشان می‌دهد.
شکل 1. عوامل شکل تلفن، تاشو، تبلت و لپ تاپ

در رایانه لوحی، یک برنامه ممکن است در حالت چند پنجره ای اجرا شود، به این معنی که برنامه ممکن است صفحه نمایش را با برنامه دیگری تقسیم کند. در ChromeOS، یک برنامه ممکن است در یک پنجره قابل تغییر اندازه باشد. حتی ممکن است بیش از یک صفحه نمایش فیزیکی مانند یک دستگاه تاشو وجود داشته باشد. در همه این موارد، اندازه فیزیکی صفحه نمایش برای تصمیم گیری در مورد نحوه نمایش محتوا مهم نیست.

در عوض، باید بر اساس بخش واقعی صفحه که به برنامه شما اختصاص داده شده است، تصمیم بگیرید، مانند معیارهای پنجره فعلی ارائه شده توسط کتابخانه Jetpack WindowManager . برای مشاهده نحوه استفاده از WindowManager در برنامه Compose، نمونه JetNews را بررسی کنید.

پیروی از این رویکرد برنامه شما را انعطاف‌پذیرتر می‌کند، زیرا در تمام سناریوهای بالا به خوبی عمل می‌کند. تطبیق طرح‌بندی‌های خود با فضای صفحه‌نمایش در دسترس آن‌ها، میزان کنترل ویژه برای پشتیبانی از پلتفرم‌هایی مانند ChromeOS و عواملی مانند تبلت‌ها و تاشوها را کاهش می‌دهد.

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

@Composable
fun MyApp(
    windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
) {
    // Perform logic on the size class to decide whether to show the top app bar.
    val showTopAppBar = windowSizeClass.windowHeightSizeClass != WindowHeightSizeClass.COMPACT

    // MyScreen knows nothing about window sizes, and performs logic based on a Boolean flag.
    MyScreen(
        showTopAppBar = showTopAppBar,
        /* ... */
    )
}

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

ترکیبات تو در تو انعطاف پذیر قابل استفاده مجدد هستند

ترکیبات زمانی که بتوان آن ها را در مکان های مختلف قرار داد، قابلیت استفاده مجدد بیشتری دارند. اگر یک Composable فرض کند که همیشه در یک مکان خاص با یک اندازه خاص قرار می گیرد، استفاده مجدد از آن در مکان های مختلف یا با مقدار متفاوتی از فضای موجود دشوارتر خواهد بود. این همچنین به این معنی است که تک تک مواد قابل استفاده مجدد باید به طور ضمنی بسته به اطلاعات اندازه "جهانی" اجتناب کنند .

مثال زیر را در نظر بگیرید: یک composable تو در تو را تصور کنید که طرح‌بندی جزئیات فهرست را پیاده‌سازی می‌کند، که ممکن است یک صفحه یا دو صفحه را در کنار هم نشان دهد.

تصویری از یک برنامه که دو صفحه را در کنار هم نشان می دهد.
شکل 2. تصویری از یک برنامه که یک چیدمان معمولی با جزئیات لیست را نشان می دهد - 1 ناحیه لیست است. 2 ، منطقه جزئیات.

ما می‌خواهیم این تصمیم بخشی از طرح‌بندی کلی برنامه باشد، بنابراین همانطور که در بالا دیدیم، این تصمیم را از یک صفحه نمایش قابل ترکیب منتقل می‌کنیم:

@Composable
fun AdaptivePane(
    showOnePane: Boolean,
    /* ... */
) {
    if (showOnePane) {
        OnePane(/* ... */)
    } else {
        TwoPane(/* ... */)
    }
}

اگر در عوض بخواهیم یک composable به طور مستقل چیدمان خود را بر اساس فضای موجود تغییر دهد، چه؟ به عنوان مثال، کارتی که می خواهد جزئیات بیشتری را در صورت اجازه فضا نشان دهد. ما می خواهیم بر اساس برخی از اندازه های موجود، منطقی را انجام دهیم، اما به طور خاص کدام اندازه؟

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

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

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

بنابراین، باید از عرضی که در واقع composable داده می شود برای رندر کردن خود استفاده کنیم. ما دو گزینه برای بدست آوردن آن عرض داریم:

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

اگر می‌خواهید چیزی را که نشان می‌دهید تغییر دهید، می‌توانید از BoxWithConstraints به عنوان جایگزین قدرتمندتری استفاده کنید. این composable محدودیت‌های اندازه‌گیری را فراهم می‌کند که می‌توانید از آن‌ها برای فراخوانی ترکیب‌پذیرهای مختلف بر اساس فضای موجود استفاده کنید. با این حال، این امر با هزینه‌هایی همراه است، زیرا BoxWithConstraints ترکیب را تا مرحله Layout، زمانی که این محدودیت‌ها شناخته می‌شوند، به تعویق می‌اندازد و باعث می‌شود کارهای بیشتری در طول طرح‌بندی انجام شود.

@Composable
fun Card(/* ... */) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(/* ... */)
                Title(/* ... */)
            }
        } else {
            Row {
                Column {
                    Title(/* ... */)
                    Description(/* ... */)
                }
                Image(/* ... */)
            }
        }
    }
}

اطمینان حاصل کنید که همه داده ها برای اندازه های مختلف در دسترس هستند

هنگام استفاده از فضای اضافی صفحه نمایش، در یک صفحه نمایش بزرگ ممکن است فضای بیشتری برای نشان دادن محتوای بیشتری به کاربر نسبت به یک صفحه نمایش کوچک داشته باشید. هنگام پیاده سازی یک Composable با این رفتار، ممکن است کارآمد بودن و بارگذاری داده ها به عنوان یک اثر جانبی اندازه فعلی وسوسه انگیز باشد.

با این حال، این در تضاد با اصول جریان داده های یک طرفه است، جایی که داده ها را می توان بالا برد و در اختیار اجزای سازنده قرار داد تا به طور مناسب ارائه شوند. داده‌های کافی باید در اختیار کامپوزیشن قرار گیرد تا دستگاه ترکیب‌پذیر همیشه آنچه را که باید در هر اندازه‌ای نمایش دهد، داشته باشد، حتی اگر بخشی از داده‌ها همیشه مورد استفاده قرار نگیرد.

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(description)
                }
                Image(imageUrl)
            }
        }
    }
}

با توجه به مثال Card ، توجه داشته باشید که ما همیشه description را به Card ارسال می کنیم. حتی اگر description فقط زمانی استفاده می‌شود که عرض اجازه نمایش آن را بدهد، Card همیشه بدون توجه به عرض موجود به آن نیاز دارد.

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

این اصل همچنین اجازه می دهد تا وضعیت را در سراسر تغییرات طرح بندی حفظ کنید. با بالا بردن اطلاعاتی که ممکن است در همه اندازه‌ها استفاده نشود، می‌توانیم وضعیت کاربر را با تغییر اندازه طرح حفظ کنیم. به عنوان مثال، می‌توانیم یک پرچم Boolean showMore را برافراشته‌ایم تا زمانی که تغییر اندازه باعث می‌شود که چیدمان بین پنهان کردن و نمایش توضیحات تغییر کند، وضعیت کاربر حفظ شود:

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    var showMore by remember { mutableStateOf(false) }

    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(
                        description = description,
                        showMore = showMore,
                        onShowMoreToggled = { newValue ->
                            showMore = newValue
                        }
                    )
                }
                Image(imageUrl)
            }
        }
    }
}

بیشتر بدانید

برای کسب اطلاعات بیشتر در مورد طرح‌بندی‌های سفارشی در Compose، به منابع اضافی زیر مراجعه کنید.

برنامه های نمونه

  • CanonicalLayouts مخزنی از الگوهای طراحی اثبات شده است که تجربه کاربری بهینه را در دستگاه های صفحه نمایش بزرگ فراهم می کند.
  • JetNews نحوه طراحی اپلیکیشنی را نشان می دهد که رابط کاربری خود را برای استفاده از فضای موجود تطبیق دهد
  • Reply یک نمونه تطبیقی ​​برای پشتیبانی از موبایل، تبلت و تاشو است
  • اکنون در اندروید برنامه ای است که از طرح بندی های تطبیقی ​​برای پشتیبانی از اندازه های مختلف صفحه نمایش استفاده می کند

ویدیوها

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}