گذار (Transition) در انیمیشن های اپلیکیشن های اندرویدی – راهنمای کاربردی


در این نوشته به معرفی برخی مفاهیم نسبتاً جدید در مورد انیمیشنهای اندروید پرداختهایم. گوگل با معرفی متریال دیزاین کمک زیادی به انیمیت کردن همه چیز در اندروید کرده و به این منظور Material motion را ارائه کرده است. بدین ترتیب میتوان از گذار (Transition) در اندروید برای ایجاد انیمیشنهای مختلف استفاده کرد.
Motion موجب ایجاد معنا میشود. اشیا بدون ایجاد وقفه در تجربه کاربر، حتی در زمان تبدیل شدن و شناسایی به وی عرضه میشوند. Motion دنیای طراحی متریال است که برای توصیف روابط فضایی، کارکردها و مقاصد به طرزی زیبا و سیال مورد استفاده قرار میگیرند.
-راهنمای متریال دیزاین
در واقع فرایند ایجاد انیمیشن زمانبر است. یک توسعهدهنده همواره وسوسه میشود که صرفاً خصوصیت (setVisibility(View.VISIBLE یک شیء را فراخوانی کند و وقت خود را صرف امور مهمتری مانند منطق تجاری ویژگیهای جدید اضافه شده به اپلیکیشن نماید. همه این موارد در اوقاتی که همه زمانبندیها منقضی شدهاند بیشتر نمود مییابند. اما به خاطر داشته باشید، هر بار که فرصتی را برای افزودن یک گذارِ معنیبخش به UI اپلیکیشن از دست میدهید، فرصت بزرگی از بین رفته است.
اینک استفاده از انیمیشن در طراحی رابط کاربری به تلاش کمتری نیاز دارد. شما میتوانید از API موجود برای Transition-ها استفاده کنید که از سوی گوگل برای ایجاد انیمیشنهای زیبا بین اکتیویتیها ارائه شده است. متأسفانه همه این امکانات تنها از نسخه 5.0 به بعد اندروید در اختیار ما قرار میگیرند؛ اما تصور کنید که این API میتواند به طرز مؤثری در موارد مختلف مورد استفاده قرار گیرد و اگر روی نسخههای قدیمیتر اندروید نیز عرضه میشد بسیار هیجانانگیزتر میبود.
بررسی تاریخچه
پارامتر جدید animateLayoutChange در نسخه 4.0 اندروید عرضه شده است. اما زمانی که آن را فراخوانی کرده و برخی موارد را درون آن پیکربندی میکنید همچنان ناپایدار است و به قدر کافی انعطافپذیری ندارد. بنابراین نمیتوانید کار زیادی با آن انجام دهید.
در نسخه 4.4 اندروید (Kitkat)، مفهوم «صحنهها» (Scenes) و «گذارها» (Transitions) معرفی شده است. صحنه از لحاظ فنی به وضعیت همه «نما» (View) ها در ریشه Scene یعنی layout container گفته میشود. گذار مجموعهای از انیمیشنها است که روی نما اعمال میشوند تا گذار همواری از یک صحنه به صحنه دیگر اجرا کند. برای روشنتر شدن موضوع در ادامه به بررسی یک مثال میپردازیم.
طراحی یک دکمه
تصور کنید یک دکمه داریم و پس از یک کلیک میخواهیم متنی به زیر دکمه اضافه شود. طرحبندی این وضعیت چنین است:
ما در جاوا یک «شنونده کلیک» (click listener) داریم. بنابراین نتیجه کار چنین است:
تا به این جا که بد نبوده است، با تنها یک خط کد توانستیم یک انیمیشن طراحی کنیم. نکته جالب در این کد آن است که «پدیداری» (visibility) متن بر حسب انیمیشن تعریف میشود؛ اما همزمان موقعیت دکمه نیز تغییر مییابد. فریمورک Transition به صورت خودکار طرحبندی را طوری انیمیت میکند که تغییر ناشی از ظاهر شدن TextView جبران شود و بنابراین لازم نیست به صورت دستی کاری انجام دهید. شما حتی میتوانید انیمیشن جدیدی را هنگامی که انیمیشن قبلی در حال اجرا است آغاز کنید. فریمورک Transition انیمیشن در حال اجرا را متوقف کرده و سپس اقدام به انیمیت کردن نماها از موقعیت فعلیشان میکند. همه این کارها در پسزمینه به شیوهای جادویی و خودکار انجام میشوند.
ما میتوانیم روش دقیق اجرای گذار را تعیین کنیم که از طریق پارامتر دوم متد beginDelayedTransition اجرا میشود.
انواع ساده گذار
- ChangeBounds: به انیمیت کردن تغییرات رخ داده در موقعیت و اندازه یک نما میپردازد. برای نمونه این نوع گذار موجب جابجایی دکمه در مثال ما شده است.
- Fade: کلاس Visibility را بسط میدهد و رایجترین انواع انیمیشنها را اجرا میکند که fade in و fade out هستند. در مثال ما روی TextView اعمال شده است.
- TransitionSet: عملاً گذار است که مجموعهای از گذارهای دیگر را در خود دارد. این گذارها میتوانند با همدیگر آغاز شوند یا به صورت ترتیبی اجرا شوند. برای تغییر دادن ترتیب آنها باید setOrdering را فراخوانی کنید.
- AutoTransition: یک «مجموعه گذار» (TransitionSet) است که شامل Fade Out ،ChangeBounds و Fade In با ترتیب متوالی است. در ابتدا نماهایی که در صحنه دوم وجود ندارند محو میشوند، سپس ChangeBounds برای تغییر موقعیت و اندازه استفاده میشود و در نهایت نماهای جدید ظاهر میشوند. به صورت پیشفرض از AutoTransition در زمانی که هیچ گذاری در آرگومان دوم beginDelayedTransition تعیین نشده باشد، استفاده میشود.
Backport
همه دوست دارند که تنها یک پیادهسازی بنویسند که رفتار سازگاری روی همه نسخههای اندروید داشته باشد. خوشبختانه ما میتوانیم در زمان استفاده از API گذار نیز به این وضعیت دست پیدا کنیم. دو کتابخانه کاملاً مشابه روی گیتهاب وجود دارند که البته مدتی است نگهداری نمیشوند و خصوصیتی که میتوانست Backport شود را از دست دادهاند. بنابراین ما یک کتابخانه جدید ایجاد کردیم و هر دو آنها را با کلی امکانات جدید برای سازگاری با نسخههای قدیمیتر اندروید اضافه کردیم. همه تغییرات API از نسخه لالیپاپ تا مارشملو نیز در آن ادغام شدهاند.
بنابراین باید گفت که کتابخانه «Transitions Everywhere» (+) یک backport برای API گذار از نسخه 4.0 اندروید به بالا است. برای شروع به استفاده از آن میتوانید یک وابستگی gradle تعیین کنید:
در مورد همه کلاسهای مرتبط نیز میتوانید دستور ایمپورت را از *.android.transition به *.com.transitionseverywhere تغییر دهید. گوگل کتابخانه پشتیبانی فریمورک Transitions را منتشر کرده است؛ اما هنوز باگهایی دارد که در کتابخانه فوق اصلاح شدهاند.
چه کارهای دیگری میتوان انجام داد؟
قبل از هر چیز میتوانیم مدت گذار را تغییر دهیم، گذارها را میانیابی کنیم و آن را با تأخیر برای انیمیشنهای درون گذار آغاز کنیم:
در ادامه نگاهی به انواع مختلف گذارهای دیگر خواهیم داشت:
Slide
این گذار نیز مانند Fade اقدام به بسط Visibility میکند. این گذار به نماهای جدید کمک میکند که در صحنه از یک سمت به سمت دیگر بروند. نمونهای از آن را به صورت (Slide(Gravity.RIGHT در ادامه مشاهده میکنید:
Explode و Propagation
Explode تا حدود زیادی شبیه به Slide است؛ اما در آن نما بسته به مرکز ثقل گذار در جهت خاصی محاسبه میشود. در این گذار شما باید مرکز ثقل را با استفاده از متد setEpicenterCallback تعیین کنید.
TransitionPropagation تأخیرهای آغاز را برای هر انیماتور محاسبه میکند. برای نمونه Explode به صورت پیشفرض از CircularPropagation استفاده میکند. تأخیر برای انیمیشن به مسافت بین نما و نقطه ثقل بستگی دارد. برای اعمال کردن آن باید setPropagation را در گذار فراخوانی کرد.
فرض کنید یک RecyclerView با GridLayoutManager داریم و میخواهیم همه عناصر را پس از یک بار ضربه روی عنصر خاص حذف کنیم. روش کار به این صورت است:
ChangeImageTransform
ChangeImageTransform به انیمیت کردن تغییرات از ماتریس تصویر میپردازد. این تبدیل برای موقعیتهایی مفید است که scaleType یک ImageView تغییر میابد. در اغلب موارد بهتر است از آن به همراه ChangeBounds برای انیمیت کردن موقعیت، اندازه و یا تغییرات scaleType استفاده کنیم.
حرکت منحنی روی مسیر
نیروهای دنیای واقعی مانند گرانش موجب میشوند که حرکت یک عنصر روی یک کمان و نه یک خط مستقیم باشد.
-راهنمای متریال دیزاین
در هر گذار که با استفاده از مختصات دوبُعدی کار میکند، برای نمونه در تغییرات موقعیت یک نما با استفاده از ChangeBounds، میتوان از حرکت منحنی با استفاده از متد setPathMotion بهره گرفت.
TransitionName
فرض کنید قصد داریم همه نماها را از کانتینر حذف کنیم و یک مجموعه جدید از نماها به آن اضافه کنیم. برخی از عناصر جدید در عمل همانند وضعیت پیش از ایجاد مجدد خواهند بود. در این حالت چگونه میتوانیم به فریمورک کمک کنیم که درک کند کدام آیتمها حذف شدهاند و کدام یک به یک موقعیت جدید جابجا شدهاند؟ این کار با فراخوانی متد استاتیک زیر به سادگی قابل اجرا است:
در متد فوق میتوانید هر نام یکتایی را بسته به مدل دادهها برای هر نما ارائه کنید.
برای نمونه اگر میخواهید لیستی از عناوین را ایجاد کنید و آن را با نماهای ایجاد شده مجدد در هر بار کلیک شدن یک دکمه به هم بریزید، میتوانید از کد زیر استفاده کنید:
Scale
این گذار در واقع بخشی از API گذار محسوب نمیشود و ما آن را اضافه کردهایم. این گذار امکان انیمیت کردن تغییرات visibility را با انیمیشن مقیاسبندی فراهم میکند.
نمونه سادهای از یک ()scale جدید به صورت زیر است:
ضمناً میتوان از این گذار به همراه گذارهای دیگر نیز استفاده کرد. برای نمونه میتوان آن را با Fade ترکیب کرد. ما میتوانیم مقیاس نهایی سفارشی خود را در قرار دهیم.
Recolor
همان طور که از نام این گذار مشخص است از آن میتوان برای انیمیت کردن تغییرات رنگ پسزمینه و/یا رنگ متن یک آیتم استفاده کرد:
Rotate
این گذار نیز نیاز به توضیح ندارد و در ادامه میتوانید نمونه کد آن را مشاهده کنید:
ChangeText
این گذار به ما کمک میکند که یک انیمیشن fade ساده برای تغییرات متنی تعریف کنیم.
Targets
پیکربندی گذارها آسان است. شما میتوانید نماهای خاصی را برای هر گذار هدفگیری کنید تا تنها این موارد انیمیت شوند. متدهایی که برای افزودن هدف قابل استفاده هستند در ادامه شرح داده شده است:
- (addTarget(View target : برای خود نما.
- (addTarget(int targetViewId : برای id نما.
- (addTarget(String targetName: روشی مشابه متد TransitionManager.setTransitionName دارد.
- (addTarget(Class targetType: برای هدفگیری یک کلاس برای نمونه به صورت android.widget.TextView.class.
برای حذف یک هدف میتوان از متدهای زیر استفاده کرد:
- (removeTarget(View target
- (removeTarget(int targetId
- (removeTarget(String targetName
- (removeTarget(Class target
برای حذف کردن برخی نماها از متدهای زیر استفاده کنید:
- (excludeTarget(View target, boolean exclude
- (excludeTarget(int targetId, boolean exclude
- (excludeTarget(Class type, boolean exclude
- (excludeTarget(Class type, boolean exclude
و برای حذف کردن همه فرزندان برخی ViewGroup-ها میتوان از متدهای زیر استفاده کرد:
- (excludeChildren(View target, boolean exclude
- (excludeChildren(int targetId, boolean exclude
- (excludeChildren(Class type, boolean exclude
ایجاد گذار با استفاده از XML
گذار میتواند در یک فایل XML نیز تعریف شود. این فایل XML باید در پوشه res/anim قرار داشته باشد. نمونهای از آن چنین است:
گذارهای اکتیویتی و فرگمان
گذارهای اکتیویتی نمیتوانند backport شوند. منطق زیادی در اکتیویتی نهفته است. همین موضوع در مورد گذارهای فرگمان نیز صدق میکند. ما باید فرگمان خاص خود را برای تغییر دادن منطق گذار ایجاد کنیم.
گذارهای سفارشی
گذارها میتوانند برای هر منظوری و برای هر نمایی مورد استفاده قرار گیرند. در ادامه برخی گذارهای سفارشی منحصر به فرد خاص خود را میسازیم. تنها کاری که باید انجام دهیم پیادهسازی سه متد captureStartValues، captureEndValues و createAnimator است. دو متد اول به دریافت حالت نما پیش و پس از تغییر صحنه میپردازند.
در ادامه گذاری برای پیشرفت هموارتر تغییرات یک ProgressBar افقی ایجاد میکنیم:
شیوه استفاده از آن نیز چنین است:
در ادامه میتوانید نتیجه کار را مشاهده کنید:
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامه نویسی اندروید
- گنجینه برنامه نویسی اندروید (Android)
- مجموعه آموزش های برنامه نویسی
- آموزش برنامه نویسی اندروید (Android) – تکمیلی
- MotionLayout و هر آنچه باید در مورد ایجاد انیمیشن در اندروید بدانید
- کار با متریال دیزاین در برنامه نویسی اندروید — بخش اول
==