ساخت یک رابط کاربری واکنش گرا در اندروید – از صفر تا صد


چیزی آزاردهندهتر از این نیست که متوجه شویم تصاویر بسیار زیبایی از رابط کاربری اپلیکیشنها که در فروشگاه گوگل پلی مشاهده میکنیم را نمیتوانیم در دستگاه خود داشته باشیم. البته بدیهی است که نمیتوان انتظار داشت همه اپلیکیشنها رابط کاربری خود را روی بیش از 11،000 دستگاه اندرویدی موجود در بازار تست کنند و خوشبختانه در صورتی که یک رابط کاربری واکنش گرا در اندروید بسازید به این کار نیازی هم نخواهد بود.
ساخت یک رابط کاربری واکنشگرا بیشتر از هر بخش دیگر از کار توسعه اندروید، یک عمل چند رشتهای محسوب میشود. همه افراد باید با هم کار کنند تا مشخص شود چه هنگام و چگونه باید رابط کاربری تغییر یابد.
انتخاب زمان تغییر رابط کاربری اپلیکیشن
یک رابط کاربری واکنشگرا صرفاً یک UI است که به مقدار فضای موجود در صفحه واکنش نشان میدهد. با این که اغلب ما وسوسه میشویم صرفاً در مورد دستگاهی که استفاده میکنیم یا یک تلفن خاص فکر کنیم، اما اندروید عمیقاً به شعار خود باور دارد: «همه کنار هم و نه یک شکل» و از این رو طیف متنوعی از دستگاهها با اندازههای مختلف وجود دارند. این نکتهای است که توسعهدهندگان وب و دسکتاپ سالها است که با آن دست و پنجه نرم میکنند.
سیستم منابع (+) در اندروید ابزارهایی برای ارائه منابع جایگزین بر مبنای عرض، ارتفاع یا کمترین عرض دستگاه در اختیار شما قرار میدهد. اینها اندازههای مهمی هستند که به عنوان مبنایی برای انتخاب زمان مناسب برای تغیر UI بر مبنای فضای موجود صفحه استفاده میشوند.
عرض و نقاط توقف
عرض صفحه احتمالاً مهمترین ابعادی است که هنگام انتخاب زمان مناسب برای تغییر رابط کاربری باید لحاظ شود. دلیل این امر آن است که عرض بر مبنای «سیستم نقاط توقف» (Breakpoint System) عمل میکند.

منظور از «نقطه توقف» یا breakpoint عرض خاصی است که رابط کاربری در آن میتواند در واکنش به فضای اضافی تغییر یابد تا بیشترین استفاده از فضای صفحه صورت بگیرد. این تفاوت میتواند بسیار کوچک (مانند حاشیههای کمی بزرگتر) یا یک تغییر بزرگتر مانند مثالهایی در بخشهای بعدی ارائه میکنیم باشد.
یک مثال خوب از این وضعیت خط 600dp است. تنها در این نقطه است که باید از دو سلسلهمراتب محتوا (برای نمونه نمای master و detail) روی صفحه به طور همزمان استفاده کنیم. زیر این نقطه اگر چنین کاری صورت بگیرد به احتمال زیاد کاربر دچار زحمت میشود.
به طور مشابه اندازههای صفحه بسیار بزرگ مانند 1600dp زمان مناسبی برای تعیین یک مقدار بیشینه عرض برای رابط کاربری هستند و در این حالت یا عناصر در راستای مرکز قرار گرفته و حاشیهها بزرگ میشوند و یا کل عناصر رابط کاربری در راستای سمت چپ صفحه قرار میگیرند.
نکته: البته منظور ما این نیست که طرحبندی شما بین دو نقطه توقف باید کاملاً استاتیک و بدون تغییر باشد. عناصر بسیار اندکی هستند که واقعاً به عرض ثابتی نیاز داشته باشند و بهتر است که عناصر در راستای شبکه انعطافپذیری (+) داشته باشند و با استفاده از درصد ثابتی از فضای موجود در صفحه چیده شوند.
برای بهرهبرداری از مزیت منابع مبتنی بر عرض، باید از پیشوند w استفاده کنید. برای نمونه یک طرحبندی پیشفرض میتواند یک layout باشد و یک طرحبندی برای عرض 600dp یا بیشتر میتواند به صورت layout-w600dp باشد.
ارتفاع

از سوی دیگر استفاده از ارتفاع به عنوان یک عنصر سطح بالا در ساخت یک رابط کاربری واکنشگرا چندان رایج نیست؛ اما این به آن معنا نیست که باید کلاً آن را کنار بگذاریم. در واقع مواردی که ارتفاع شدیداً محدود هستند جزو مواردی هستند که رابط کاربری میتواند این محدودیت را کاهش دهد.
برای نمونه حالت 16:9 را با پنجرههای افراز صفحه روی گوشیهای تلفن همراه تصور کنید. چنین ارتفاع کمی میتواند موجب شود که اینترفیسها که به طور سنتی استفاده آسانی دارند (مانند کانتینرهای با اسکرول افقی) به گزارههای دشواری تبدیل شوند. همانند زمان شناسایی منابع با عرض، در مورد ارتفاع نیز از پیشوند h مانند layout-h480dp استفاده میکنیم.
رابطهای کاربری با مشخصات کمترین عرض و حساس به چرخش
به طور طبیعی توسعهدهندگان میل دارند که فضای موجود را بر مبنای اندازه کلی دستگاه محاسبه کنند. به همین دلیل است که اغلب میشنویم افراد میگویند: «میخواهیم یک UI تبلت بسازیم.» اما واقعیت این است که نه عرض و نه ارتفاع، مقدار کلی اندازه دستگاه را مشخص نمیکنند؛ بلکه هر کدام از آنها صرفاً یک بعد را اندازهگیری میکنند. اما بدیهی است که طرحبندیهایی مانند layout-w600dp-h600dp نیز پاسخگو نیستند و از این رو طرحبندیهایی به نام کمترین عرض یا layout-sw600dp وجود دارند.
کمترین عرض
کمترین عرض بر اساس انتخاب عرض یا ارتفاع هر کدام که کوتاهتر باشد محاسبه میشود. برای نمونه اگر یک اپلیکیشن دارای جهتگیری عمودی باشد، کمترین عرض کنونی است. زمانی که دستگاه چرخش یافت، با این که جای عرض با ارتفاع عوض شده است؛ اما کمترین عرض تغییر نمییابد.
بدین ترتیب کمترین عرض به بازنمایی کلی مناسبی از میزان فضای موجود در صفحه تبدیل میشود. این معیار همچنین در زمان ایجاد رابطهای کاربری حساس به چرخش بسیار مهم است. این بدان معنی است که عملیات در هر جهتی ممکن هستند و این که الگوهای استفاده اولیه در زمان چرخش نیز حفظ میشوند.
حساس به چرخش
این وضعیت به طور خاص هنگام آمادهسازی اپلیکیشن برای حالت چند پنجرهای در اندروید N اهمیت مییابد.
حتی اگر دستگاه شما افقی باشد، اپلیکیشن شما ممکن است در جهتگیری عمودی باشد. در واقع منظور از عمودی صرفاً این است که ارتفاع بزرگتر از عرض است و منظور از افقی نیز این است که عرض بزرگتر از ارتفاع است. اپلیکیشن میتواند از یک وضعیت به وضعیت دیگر انتقال یابد و دچار تغییر اندازه شود.
اگر از حالتهای portrait یا landscape برای تغییر رابط کاربری خود استفاده کنید، ممکن است شما و کاربرانتان هنگام تغییر اندازه دادن اپلیکیشن تا آن عدد جادویی بین تغییر از حالت عمودی به افقی پیش نیامده دچار شگفتزدگی شوند. شما باید این اطمینان را حاصل کنید که کاربرانتان در این خصوص شگفتزده میشوند.
البته این بدان معنی نیست که هیچ چیز را نمیتوان بین دو جهتگیری تغییر داد؛ اما باید تغییرات ساختاری/ناوبری بزرگتر را در صورتی که چنین تغییراتی اصولاً مورد نیاز باشند، بر اساس کمترین عرض اجرا کنید.
انتخاب مواردی که باید تغییر کنند
ما با تصمیمگیری در مورد زمان تغییر تنها نیمی از معادله را تا به اینجا حل کردهایم. دانستن این که چه چیزی و چگونه باید تغییر یابد نیز به همان اندازهی تعیین زمان تغییر مهم است.
چندین الگو (+) برای رابط کاربری واکنشگرا وجود دارند که میتوانید مورد بررسی قرار دهید و در مورد زمان استفاده از یک تغییر برحسب فضای مورد نیاز تصمیمگیری کنید.
افشا (Reveal)
نخستین الگویی که بررسی میکنیم شامل افشای محتوای پنهان در زمان به دست آوردن فضای اضافی است. این الگو تعادلی بین نیازهای صفحه کوچک (که در آنجا با کمبود فضا مواجه میشویم) و نیازهای صفحه بزرگ برقرار میکند که در آن جا میتوانیم تعداد ضربههای کاربر را کاهش دهیم و اطلاعات پنهان را به کاربر نمایش دهیم و به این ترتیب تجربه کاربری وی را بهبود ببخشیم.
این الگو در هنگام استفاده از layout-ها بسیار رایج است. در صفحه کوچکتر، ممکن است به تعاملهای خاص کاربر (مانند ضربه زدن روی یک دکمه) برای گسترش دادن فیلدهای کمتر استفاده شده نیاز داشته باشیم.
با این حال، در صفحههای بزرگتر همه فیلدها به طور پیشفرض میتوانند نمایش یابند.
راهحل: دو layout با نام یکسان، یکی در دایرکتوری layout و دیگری در دایرکتوری layout-w600dp ایجاد میکنیم. مطمئن میشویم که فراخوانیهای ()findById برای مقادیر تهی برای view-ها تنها در یکی از لیآوت ها ظاهر میشود.
تبدیل (Transform)
در الگوی تبدیل یا Transform، چیزهایی که روی صفحه نمایش مییابند، تغییر پیدا نمیکنند؛ بلکه قالب یا سبک استفاده از آنها عوض میشود. سادهترین مثال منویی است که عناصر آن دارای خصوصیت "showAsAction=”ifRoom هستند. زمانی که کاربر فضای بیشتری روی صفحه پیدا کند، عناصر میتوانند از یک منوی overflow به آیتمهای toolbar تبدیل شوند و از قالب متنی به آیکون تغییر ساختار بدهند.
نمونه دیگر برای تبدیل، شیوه نمایش مجموعههای داده است.
یک لیست با قابلیت پیمایش آسان در عرض محدود کارایی مناسبی دارد؛ اما تبدیل آن به یک لیست با عرض زیاد میتواند کاری دشوار باشد. تبدیل کردن همان مجموعه به یک شبکه (grid) میتواند برای بهرهبرداری بهینه از فضا و اولویت دادن به محتوا مناسب باشد.
راهحل: میتوان با بهرهگیری از خصوصیت RecyclerView در layoutManager شیوه نمایش را از LinearLayoutManager به GridLayoutManager تغییر داد و هیچ کدی را نیز در اپلیکیشن تغییر نداد. در این مورد باید مطمئن شوید که view ایجاد شده در ()onCreateViewHolder نیز در همان نقطه توقف layoutManager شما تغییر پیدا میکند.
تقسیم (Divide)
زمانی که صفحه خود را تقسیم میکنید از فضای اضافی موجود روی صفحه برای نمایش قطعات چندگانه رابط کاربری به طور همزمان بهره میگیرید. این وضعت شباهت زیادی به الگوی افشا دارد؛ اما بیشتر روی تغییر دادن عناصر سطح بالا و ناوبری برای قطعهبندی صفحه تمرکز دارد تا صرفاً نمایش کانتینرهای موجود.
یک مکان عالی برای استفاده از این الگو زمانی است که چندین برگه دارید که خودشان دارای ماهیتی نسبتاً ساده هستند.
به جای اعمال یک الگوی متفاوت در مورد هر یک از برگههای منفرد (که اینک بزرگتر هم هستند) میتوانید صفحه را تقسیم کنید و هر بخش محتوا را در کلیت خودش نمایش دهید.
راهحل: در دستگاههای کوچکتر باید یک رابط کاربری با استفاده از Tabs و ViewPager بسازید که ترجیحاً به وسیله یک فرگمان برای هر صفحه ایجاد میشود. همچنین اولویت در این روش استفاده از کمترین عرض و استفاده از یک لیآوت است که به طور مستقیم هر فرگمان منفرد را به صفحه اضافه کند.
Reflow
الگوی Reflow بر روی انعطافپذیری بخشهای زیرساختی رابط کاربری تکیه دارد و میتواند در سطح خرد یا کلان اجرا شود. برای نمونه یک View-ی منفرد زمانی که عرض آن به بیشینه مقدار رسید، میتواند به طور عمودی محتوای خود را روی هم انباشته میکند؛ اما در صورتی که نیاز به عرض بیشتری باشد میتواند به صورت افقی این انباشت را انجام دهد.
همین مفهوم در مورد کل رابط کاربری شما نیز مصداق دارد یعنی میتوان همه view-ها را برای پر کردن فضای موجود reflow کرد.
View-ها در دستگاههای کوچکتر در یک ستون منفرد چیده شدهاند و میتوانند reflow شده و در چندین ستون قرار گیرند.
راهحل: اگر محتوای دینامیک داشته باشید، میتوانید از یک StaggeredGridLayoutManager استفاده کنید و با بهرهگیری از app:spanCount در XML یا ()setSpanCount به صورت دینامیکی تعداد ستونها را تغییر دهید.
نکته: ما تا به اینجا در مورد واکنشگرا کردن لیآوت ها با استفاده از عرض، ارتفاع و کمترین عرض، زیاد صحبت کردیم؛ اما این تکنیک در مورد همه انواع منابع استفاده میشود. به جای ساختن فایلهای xml متفاوت، کافی است spanCount را تغییر دهیم و آن را به یک منبع integer تبدیل کنیم که یک مقدار جایگزین در پوشه منبع values-w600dp ارائه میدهد.
گسترش (Expand)
همه تغییراتی که در زمان تغییر اندازه صفحه مورد نیاز هستند، تغییرات بزرگ نیستند و در پارهای موارد نیز صرفاً به تغییرات کوچکی نیاز داریم. گسترش دادن فضای موجود برای رابط کاربری (یا اضافه کردن حاشیههای بیشتر) میتواند روش مؤثری برای تغییر رابط کاربری در این موارد باشد.
راهحل: همان طور که قبلاً اشاره کردیم، هر منبعی میتواند در برابر تغییراتی که در عرض، ارتفاع و کمترین عرض رخ میدهد، واکنشگرا باشد. این نوع گسترش در واقع با افزودن حاشیه آسانتر صورت میپذیرد. در این موارد میتوان در دستگاههای با عرض کمتر از حاشیه 0dp و در دستگاههای بزرگتر از حاشیه 24dp استفاده کرد. یک راهحل دیگر استفاده از کتابخانه Percent Support (+) است که برای نمونه میتواند layout_widthPercent را از 100% به 80% تغییر دهد. اما اگر میخواهید یک عرض بیشینه روی کل view تعیین کنید باید از تنظیم MaxWidthLinearLayout استفاده کنید.
موقعیت (Position)
آخرین الگوی تغییر رابط کاربری که در این نوشته بررسی میکنیم تغییر دادن موقعیت view-های مهم است که میتواند همه تغییرات مورد نیاز و قابلاجرا در یک رابط کاربری را تشکیل دهد.
برای نمونه FloatingActionButton (+) یا به اختصار FAB را در نظر بگیرید. بر اساس تعریف این دکمه باید به یکی از اعمال اولیه که کاربر میخواهد انجام دهد وابسته باشد. به طور خاص اگر عناصر دیگر تغییر یابند، باید آن را بر اساس راهنماییهایی که از سوی گوگل برای استفاده از FAB روی صفحههای بزرگتر (+) ارائه شده است تغییر داد.
این وضعت ممکن است به آن معنی باشد که دکمه اقدام از محل پیشفرض خود در گوشه سمت راست و پایین تغییر موقعیت داده و به یک نوار گسترش یافته اپلیکیشن یا یک نوار ابزار و یا برگهای درون خود لیآوت اتصال یابد.
راهحل: فرض کنید از دکمه FloatingActionButton با یک CoordinatorLayout استفاده میکنید. این دکمه در گوشه راست-پایین صفحه با خصوصیت "layout_gravity=”bottom|end قرار گرفته است در حالی که شما باید از layout_anchor با استفاده از ارتفاع افزایش یافته AppBarLayout و خصوصیت layout_anchorGravity=”bottom|end” استفاده کنید تا FAB را به AppBarLayout الصاق کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامه نویسی اندروید
- آموزش برنامه نویسی اندروید (Android) – مقدماتی
- مجموعه آموزشهای برنامهنویسی
- ۵ نکته برای شروع برنامهنویسی اندروید
- آموزش ساخت اپلیکیشن اندروید (Android) با PHP و MySQL
==