
انیمیشن ها در طراحی رابط کاربری اندروید قدرت فوق العاده ای در ایجاد احساس تعامل با نرم افزار در کاربر ایجاد میکند .کاربر دکمه ای را در نرم افزار لمس میکند و المان ها با ایجاد کنش حرکتی نشان میدهند خواسته کاربر را درک میکنند .با استفاده از API های که در این خصوص ساخته شده ، میتوان هر چیز در در صفحه حرکت داد ، از یک دکمه ساده گرفته تا حتی تصاویر ایکون ها . انیمیشن در اندروید در سه چارچوب ارائه شده که هر کدام برای وضعیت های مختلف طراحی شده :
انیمیشن خصوصیات ( Property Animations ) : رابط ی پر قدرت که از اندروید 3 معرفی شده و خصوصیات المان ها را انیمیت می کند
انیمیشن ویو ( View Animations ) : رابطی کند و کمتر استفاده در مقابل Property Animations که View ها را انیمیت میکند
انیمیشن جابجای ( Transition Animations ) : برای اجرا در اندروید 4.4 به بالاتر ساخته شده که جابجایی بین اکتیویتی ها و فرگمنت ها را انیمیت می کند
در این چارچوب ها 5 قالب انیمیشن قابل طراحی است و تمام کلاس ها و رابط های برنامه نویسی طراحی شده در این قالب ها جای میگیرند :
انیمیت خصوصیت ( Property Animations ) : این انیمیت برای تغییر یک خصوصیت بین دو مقدار می باشد و معمولا برای انیمیت کردن view ها در صفحه با چرخش و تغییر مکان و غیره انجام میگیرد
انیمیت جابجایی اکتیویتی ( Activity Transitions ) : این انیمیت در زمان ورود یا خروج اکتیویتی از صفحه اجرا میشود .
انیمیت جابجایی فرگمنت ( Fragment Transitions ) : این انیمیت در زمان جابجایی بین فرگمنت ها در صفحه اجرا میشود .
انیمیت لی اوت ( Layout Animations ) : این انیمیت روی لی اوت ها یا ViewGroup ها اجرا میشود و تمام المان های داخل لی اوت را انیمیت می کند .
انیمیت تصاویر ( Drawable Animations ) : این انیمیت برای تغییر تصاویر drawable بصورت انیمیشن اجرا میشود .
این نوع انیمیشن از اندروید 3 معرفی شده و با آن میتوان هر چیزی را در صفحه طبق روش های تعریف شده انیمیت کرد . بطور مثال متداول ترین روش های انیمیت در زیر معرفی شده .
alpha ( محو شدگی )
rotation, rotationX, rotationY ( چرخش و یا برگرداندن )
scaleX, scaleY ( بزرگنمایی یا کوچک کردن )
x, y, z ( جابجایی )
translationX, translationY, translationZ (API 21+) ( موقعیت دهی )
همانطور که می بینید این نوع انیمیشن روی روش های انیمیت کردن متمرکز شده و برایش فرقی ندارد که المان مورد نظر از چه نوعی میباشد و با آن میتوان به راحتی انیمیشن های گسترده ای ایجاد کرد . در زیر به انواع کلاس های طراحی شده برای اینکار خواهیم پرداخت
با استفاده از کلاس ObjectAnimator می توان خصوصیات مختلف یک view را انیمیت کرد . متد های طراحی شده در این کلاس view مورد نظر و روش انیمیت و مقدار نهایی را دریافت کرده و خودش بقیه کار را به عهده میگرد .
ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(tvLabel, "alpha", 0.2f); fadeAnim.start();
در کد بالا tvLabel یک view برای انیمیت کردن و رشته ی "alpha" با استفاده از reflection خصوصیت مورد نظر برای انیمیت کردن را پیدا کرده و آن را تا مقدار 0.2f انیمیت خواهد کرد . البته میتوان به جای این کار از properties system in 4.0 استفاده کرد تا سرعت اجرا نیز بیشتر شود . زیرا اینکار دیگر نیاز به جستجوی خصوصیات در reflection نخواهد داشت .
ObjectAnimator fadeAltAnim = ObjectAnimator.ofFloat(image, View.ALPHA, 0, 1); fadeAltAnim.start();
در ObjectAnimator میتوان از روش های انیمیت شامل ALPHA, ROTATION, ROTATION_X, ROTATION_Y, SCALE_X, SCALE_Y, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, X, Y, Z استفاده کرد . همچینین میتوان مدت زمان و تکرار انیمیشن را نیز تعریف کرد .
ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(tvLabel, "scaleX", 1.0f, 2.0f); scaleAnim.setDuration(3000); scaleAnim.setRepeatCount(ValueAnimator.INFINITE); scaleAnim.setRepeatMode(ValueAnimator.REVERSE); scaleAnim.start();
در ضمن AnimatorListenerAdapter رویداد های را در حین اجرای انیمیشن در اختیار ما قرار میدهد تا بتوان کنترل درستی روی اجرای انیمیشن داشت .
ObjectAnimator anim = ObjectAnimator.ofFloat(v, "alpha", 0.2f); anim.addListener(new AnimatorListenerAdapter() { @Override public void (Animator animation) { Toast.makeText(MainActivity.this, "End!", Toast.LENGTH_SHORT).show(); } }); anim.start();
گاهی اوقات نیاز است که چند انیمیت با هم اجرا شوند. کلاس AnimatorSet برای اینکار طراحی شده و با تعریف ObjectAnimator ها آنها را با هم اجرا میکند :
AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(tvLabel, "scaleX", 1.0f, 2.0f) .setDuration(2000), ObjectAnimator.ofFloat(tvLabel, "scaleY", 1.0f, 2.0f) .setDuration(2000), ObjectAnimator.ofObject(tvLabel, "backgroundColor", new ArgbEvaluator(), /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF) .setDuration(2000) ); set.start();
این انیمیشن که بالاتر از ObjectAnimator قرار خواهد گرفت ، انیمیشن های سریعتری را اجرا خواهد کرد میتوان با آن خصوصیاتی را تغییر داد
در صورت استفاده نکردن از Support Library میتوان بصورت مستقیم از آن استفاده کرد
Button btnExample = (Button) findViewById(R.id.btnExample); btnExample.animate().alpha(0.2f).xBy(-100).yBy(100);
با این انیمیشن هم میتوان خصوصیاتی زیادی را بصورت موازی تغییر داد و زمان اجرای انیمیشن و رویداد های آن را تغییر داده و انمیشن های پیچیده نوشت
btnExample.animate().alpha(0.5f).rotation(90f). scaleX(2).xBy(100).yBy(100).setDuration(1000).setStartDelay(10). setListener(new AnimatorListenerAdapter() { @Override public void (Animator animation) { Toast.makeText(MainActivity.this, "Started...", Toast.LENGTH_SHORT).show(); }; });
زمانی که ازSupport Library استفاده میکنید و در گرادل کد زیر را اضافه کردید:
implementation 'com.android.support:support-v4:24.2.0'
باید به این شکل از انیمیشن استفاده کنید تا در اندروید با API 11 نیز قابل اجرا باشد :
Button btnExample = (Button) findViewById(R.id.btnExample); ViewCompat.animate(btnExample).alpha(0.2f).xBy(-100).yBy(100);
میتوان انیمیشن ها را در فایل های xml نیز تعریف کرد . که در مسیر res/animator قرار خواهد گرفت . و فایل آن بصورت زیر خواهد بود
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together" > <objectAnimator android:propertyName="alpha" android:valueTo="0.5" > </objectAnimator> <objectAnimator android:propertyName="rotation" android:valueTo="90.0" > </objectAnimator> <objectAnimator android:propertyName="scaleX" android:valueTo="2.0" > </objectAnimator> <objectAnimator android:propertyName="translationX" android:valueTo="100.0" > </objectAnimator> <objectAnimator android:propertyName="translationY" android:valueTo="100.0" > </objectAnimator> </set>
و اینطوری از آن استفاده خواهد شد
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.multi_button); anim.setTarget(tvBlah); anim.setDuration(1000); anim.setStartDelay(10); anim.addListener(new AnimatorListenerAdapter() { @Override public void (Animator animation) { Toast.makeText(MainActivity.this, "Started...", Toast.LENGTH_SHORT).show(); }; }); anim.start();
برخی از اوقات بجای تغییر خصوصیت یک view نیاز است که روی روند اجرای انیمیشن کنترل داشته باشیم . برای این شرایط ValueAnimator گزینه بسیار خوبی است .
ValueAnimator valueAnim = ValueAnimator.ofFloat(0, 1); valueAnim.setDuration(700); valueAnim.setInterpolator(new DecelerateInterpolator()); valueAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float animatedValue = (float) animation.getAnimatedValue(); } }); if (!valueAnim.isStarted()) { valueAnim.start(); }
این نوع انیمیشن قبل از Property Animations معرفی شده بود و سیستمی کند تر دارد . معمولا نسبت به آن کمتر کاربرد دارد .
فایل انیمیشن در مسیر res/anim قرار خواهد گرفت و معمولا بصورت زیر ساخته میشود :
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" > <alpha android:duration="1000" android:interpolator="@android:anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" /> </set>
حال بصورت زیر از ان استفاده خواهیم کرد :
Animation animFadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out); animFadeOut.setAnimationListener(new AnimationListener() { @Override public void (Animation animation) { // Fires when animation starts } @Override public void (Animation animation) { // ... } @Override public void onAnimationRepeat(Animation animation) { // ... } }); // start the animation btnExample.startAnimation(animFadeOut);
همانند انیمیشنی که برای view ها اجرا کردیم میتوان برای زمان انتقال اکتیویتی نیز انیمیشن اجرا کرد و اینکار معمولا در زمان ساختن intent انجام میگیرد :
Intent i = new Intent(MainActivity.this, SecondActivity.class); startActivity(i); overridePendingTransition(R.anim.right_in, R.anim.left_out);
پارامتر اول انیمیشن ورود به صفحه و پارامتر دوم انیمیشن خروج از صفحه می باشد که بصورت فایل xml تعریف شده است :
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator"> <translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="500"/> </set>
و برای اینکه بتوان موقع برگشت به صفحه ( زدن دکمه back ) نیز انیمیشن بصورت برعکس اجرا شود باید فایل های xml جدا و بصورت برعکس را ایجاد کرده و در رویداد مورد نظر آن را صدا زد
@Override public void onBackPressed() { finish(); overridePendingTransition(R.anim.left_in, R.anim.right_out); }
کلاس Transitions API معرفی شده در اندروید 5 انیمیشن انتقال اکتیویتی را راحتر کرده ولی امکان استفاده از ان در ورژن های قبل از اندروید 5 وجود ندارد . برای اینکار کافی است در مسیر res/transition فایل های xml با تگ های slide, fade, explode, autoTransition, و recolor ایجاد کنیم
<slide xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:slideEdge="right" android:duration="1000"/>
و به این صورت از ان استفاده کنیم :
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { Transition transition =TransitionInflater.from(this).inflateTransition(R.transition.slide_right); getWindow().setExitTransition(transition);
کد بالا برای انیمیشن خروج اکتیویتی می باشد که در جای خود تعریف شده و در واقع 4 حالت میتوان انیمیشن تعریف کرد ، ورود / خروج - بازگشت / ورود مجدد . برای تعریف انیمیشن ورود به صفحه باید هنگام تعریف intent آن را تعریف کرد
Intent i = new Intent(MainActivity.this, SecondActivity.class); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this); startActivity(i, options.toBundle());
در صورتی که انیمیشن های بازگشت / ورود مجدد تعریف نشوند ، همان انمیشن های ورود و خروج بصورت برعکس اجرا خواهد شد ولی اگر بخواهید انیمیشنی برای بازگشت اجرا شود باید بجای متد finish از متد finishAfterTransition استفاده کنید . برای دیدن نمونه های مختلف استفاده از این نوع انیمیشن به اینجا و اینجا و اینجا و اینجا و اینجا و اینجا سر بزنید
میتوان انیمیشن پیش فرض در مسیر res/styles.xml را در theme نیز تغییر داد .
<style name="AppTheme" parent="AppBaseTheme"> <item name="android:windowAnimationStyle">@style/CustomAnimation.Activity</item> </style> <style name="CustomAnimation.Activity" parent="@android:style/Animation.Activity"> <item name="android:activityOpenEnterAnimation">@anim/slide_in_right</item> <item name="android:activityOpenExitAnimation">@anim/slide_out_left</item> <item name="android:activityCloseEnterAnimation">@android:anim/slide_in_left</item> <item name="android:activityCloseExitAnimation">@android:anim/slide_out_right</item> </style>
فرگمنت ها را نیز همانند اکتیویتی میتوان هنگام انتقال انیمیت کرد . برای اینکار کافی ایست مثل اکتیویتی در مسیر res/anim فایل xml ایجاد کرد
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="-50%p" android:toXDelta="0" android:duration="@android:integer/config_mediumAnimTime"/> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="@android:integer/config_mediumAnimTime" /> </set>
و سپس در هنگام ایجاد فرگمنت با استفاده از setCustomAnimations آنها را صدا زد
FragmentTransaction fts = getSupportFragmentManager().beginTransaction(); // Configure the "in" and "out" animation files fts.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right); // Perform the fragment replacement ft.replace(R.id.fragment_container, newFragment, "fragment"); // Start the animated transition. ft.commit();
در ضمن اندروید یکسری انیمیشن های از پیش تعریف شده را در مسیر R.anim دارد که میتوان مستقیم به آن دسترسی داشته و در انیمیشن استفاده کرد . برای خواندن مطالب بیشتر به اینجا مراجعه کنید
FragmentTransaction fts = getSupportFragmentManager().beginTransaction(); fts.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right); fts.replace(R.id.fragment_container, newFragment, "fragment"); fts.commit();
می توان برای هر layout انیمیشنی را تعریف کرد که هنگام ظاهر شدن در صفحه اجرا شود . برای اینکار کافی است انیمیشن مورد نظر را در فایل xml در مسیر res/anim ایجاد کنید
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"> <translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="1000" /> </set>
و سپس یک فایل xml دیگر با تگ layoutAnimation میسازیم و انیمیشن مورد نظر را ادرس دهی میکنیم
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="30%" android:animationOrder="reverse" android:animation="@anim/slide_right" />
حال در android:layoutAnimation در فایل لی اوت آن را قرار میدهیم
<LinearLayout ... android:layoutAnimation="@anim/layout_bottom_to_top_slide" />
به همین سادگی هنگام شروع برنامه تمام view هایی که در این لی اوت قرار دارند زمان ظاهر شدن در صفحه با انیمیت خواهند شد
در اندروید 5 امکانات مختلفی برای انیمیشن طبق زبان طراحی متریال معرفی شده که کار انیمیت کردن زیبا تر می کند
المان اشتراکی در انیمیشن انتقال اکتیویتی - Shared Element Activity Transition :
در این انیمیشن با معرفی یک المان مشترک در دو اکتیویتی میتوان انیمیشنی ساخت که در هر دو اکتیویتی برای همان المان اجرا شود بصورت ادامه دار اجرا شود .
انیمیشن موجی - Ripple Animation :
این انیمیشن با ایجاد افکتی مثل موج پس از لمس المان ایجاد میشود
انیمیشن ظاهر شونده - Circular Reveal Animation
این انیمیشن یک انیمیت ظاهر شونده دایره ای است که بیشتر در float button اعمال میشود
انیمیشن سلسه مراتبی - View Hierarchy Animations
در این انیمیشن با تعریف مراحل بصورت Scene کنترلی روی اجرای انیمیشن خواهیم داشت
در پایان چند کتابخانه مهم برای انیمیشن در اندروید را معرفی میکنم :
ViewAnimator - AndroidViewAnimations - RecyclerView Animators - ListViewAnimations - NineOldAndroids - Leonids - Like Button