Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Animation 10% 더 활용하기

Sungyong An
September 19, 2019

Android Animation 10% 더 활용하기

Android Platform의 Animation을 모두 알아본다.
- Drawable Animation
- Animator
- Interpolator
- ViewPropertyAnimator
- View Animation
- DynamicAnimation
- Transition

Sungyong An

September 19, 2019
Tweet

More Decks by Sungyong An

Other Decks in Programming

Transcript

  1. animation 10% • "a method in which pictures are manipulated

    to appear as moving images." Animation Link: https://en.wikipedia.org/wiki/Animation
  2. animation 10% • Drawable Animation • View Animation • Animator

    • ViewPropertyAnimator • StateListAnimator • CircularReveal animation • Interpolator • DynamicAnimation • Transition • Shared Elements • MotionLayout • 3rd party Library (ex. Lottie) ❌ ❌
  3. animation 10% AnimationDrawable // AnimationDrawable.java private void setFrame( int frame,

    boolean unschedule, boolean animate) { ... selectDrawable(frame); ... scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]); }
  4. animation 10% AnimationDrawable // AnimationDrawable.java private void setFrame( int frame,

    boolean unschedule, boolean animate) { ... selectDrawable(frame); ... scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]); }
  5. animation 10% AnimationDrawable // AnimationDrawable.java private void setFrame( int frame,

    boolean unschedule, boolean animate) { ... selectDrawable(frame); ... scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]); }
  6. animation 10% • ױੌ Animationী ৈ۞ ੢੄ ੉޷૑ܳ ࢎਊೠ׮. •

    ೞ૑݅, • ࠗ٘۞਍ Animationਸ ࠁৈ઱۰ݶ ݆਷ ੉޷૑о ೙ਃೞ׮. (60fps) • ௾ ੉޷૑ܳ ৈ۞੢ ࢎਊೞݶ ݫݽܻ ޙઁо ѣ੿ػ׮. (OOM) ױࣽೠ Frame Animation AnimationDrawable
  7. animation 10% • AnimationDrawable • AnimatedVectorDrawable • AnimatedStateListDrawable • AnimatedRotateDrawable

    • AnimatedImageDrawable Animationਸ ૑ਗೞח Drawable Drawable Animation
  8. animation 10% • AnimationDrawable • AnimatedVectorDrawable • AnimatedStateListDrawable • AnimatedRotateDrawable

    • AnimatedImageDrawable Animationਸ ૑ਗೞח Drawable Drawable Animation
  9. animation 10% DrawableInflater Link: http://androidxref.com/9.0.0_r3/xref/frameworks/base/graphics/java/android/ graphics/drawable/DrawableInflater.java#148 • res/drawable/{file_name}.xml <animated-selector />

    <ripple /> <animated-vector /> <rotate /> <animated-rotate /> <animation-list /> <animated-image /> ... -> AnimatedStateListDrawable -> RippleDrawable -> AnimatedVectorDrawable -> RotateDrawable -> AnimatedRotateDrawable -> AnimationDrawable -> AnimatedImageDrawable ...
  10. animation 10% • ੌ߈੸ਵ۽ Drawable Animation਷ द੘/઺૑݅ оמೞ׮. Animatable android.graphics.drawable

    public interface Animatable { void start(); void stop(); boolean isRunning(); }
  11. animation 10% • Notification SmallIcon਷ 24 x 24 ௼ӝܳ ӂ੢ೠ׮.

    • ૑ਗೞח Drawable ഋध: • AnimationDrawable • AnimatedVectorDrawable • ex) ౵ੌ ׮਍۽٘ ઺ ੌ ٸ, ਑૒੉ח ই੉௑ ಴द ঌܿ ই੉௑ী Animation ಴द Animated Notification Icon Link: ExpandableNotificationRow.java#392 API 21
  12. animation 10% • res/drawable/stat_sys_download.xml Animated Notification Icon <animation-list android:oneshot="false"> <item

    android:drawable="@drawable/stat_sys_download_anim0" android:duration="200" /> <item android:drawable="@drawable/stat_sys_download_anim1" android:duration="200" /> ... </animation-list>
  13. animation 10% • res/drawable/stat_sys_download.xml Animated Notification Icon <animation-list android:oneshot="false"> <item

    android:drawable="@drawable/stat_sys_download_anim0" android:duration="200" /> <item android:drawable="@drawable/stat_sys_download_anim1" android:duration="200" /> ... </animation-list>
  14. animation 10% AnimatedStateListDrawable <selector> <item android:id="@+id/selected" android:drawable="@drawable/ic_battery_100" android:state_checked="true" /> <item

    android:id="@+id/unselected" android:drawable="@drawable/ic_battery_0" android:state_checked="false" /> </selector> API 21
  15. animation 10% <animated-selector> <item android:id="@+id/selected" android:drawable="@drawable/ic_battery_100" android:state_checked="true" /> <item android:id="@+id/unselected"

    android:drawable="@drawable/ic_battery_0" android:state_checked="false" /> </animated-selector> AnimatedStateListDrawable API 21
  16. animation 10% android:id="@+id/selected" android:drawable="@drawable/ic_battery_100" android:state_checked="true" /> <item android:id="@+id/unselected" android:drawable="@drawable/ic_battery_0" android:state_checked="false"

    /> <transition android:drawable="@drawable/ad_battery_select" android:fromId="@id/unselected" android:toId="@id/selected" /> <transition android:drawable="@drawable/ad_battery_unselect" android:fromId="@id/selected" android:toId="@id/unselected" /> </animated-selector> AnimatedStateListDrawable API 21
  17. animation 10% <!-- res/drawable/ad_battery_select.xml --> <animation-list android:oneshot="true"> <item android:drawable="@drawable/ic_battery_0" android:duration="32"

    /> <item android:drawable="@drawable/ic_battery_20" android:duration="32" /> ... </animation-list> AnimatedStateListDrawable API 21
  18. animation 10% + AnimatedVectorDrawable <selector> <item android:id="@+id/selected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="true" />

    <item android:id="@+id/unselected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="false" /> </selector> API 21
  19. animation 10% <selector> <item android:id="@+id/selected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="true" /> <item android:id="@+id/unselected"

    android:drawable="@drawable/ic_nav_agenda" android:state_checked="false" /> </selector> + AnimatedVectorDrawable API 21
  20. animation 10% + AnimatedVectorDrawable <selector> <item android:id="@+id/selected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="true" />

    <item android:id="@+id/unselected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="false" /> </selector> API 21
  21. animation 10% <animated-selector> <item android:id="@+id/selected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="true" /> <item android:id="@+id/unselected"

    android:drawable="@drawable/ic_nav_agenda" android:state_checked="false" /> </animated-selector> + AnimatedVectorDrawable API 21
  22. animation 10% <item android:id="@+id/selected" android:drawable="@drawable/ic_nav_agenda" android:state_checked="true" /> <item android:id="@+id/unselected" android:drawable="@drawable/ic_nav_agenda"

    android:state_checked="false" /> <transition android:drawable="@drawable/avd_nav_schedule_select" android:fromId="@id/unselected" android:toId="@id/selected" /> </animated-selector> + AnimatedVectorDrawable API 21
  23. animation 10% <animated-vector> <aapt:attr name="android:drawable"> <vector android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">

    <path android:name="calendar" android:pathData="M 9.5 15 C 10.881 15 12 ..." android:fillColor="#ffffff" android:fillAlpha="0.7"/> </vector> </aapt:attr> <target android:name="calendar"> <aapt:attr name="android:animation"> + AnimatedVectorDrawable API 21
  24. animation 10% <animated-vector> <aapt:attr name="android:drawable"> <vector android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">

    <path android:name="calendar" android:pathData="M 9.5 15 C 10.881 15 12 ..." android:fillColor="#ffffff" android:fillAlpha="0.7"/> </vector> </aapt:attr> <target android:name="calendar"> <aapt:attr name="android:animation"> <set> <objectAnimator android:propertyName="pathData" android:duration="400" android:valueFrom="M 9.5 15 C 10.881 15 12 13.881 12 12..." android:valueTo="M 9.49 14.6 C 10.607 14.6 11.99 13.481..." + AnimatedVectorDrawable API 21
  25. animation 10% <animated-vector> <aapt:attr name="android:drawable"> <vector android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">

    <path android:name="calendar" android:pathData="M 9.5 15 C 10.881 15 12 ..." android:fillColor="#ffffff" android:fillAlpha="0.7"/> </vector> </aapt:attr> <target android:name="calendar"> <aapt:attr name="android:animation"> <set> <objectAnimator android:propertyName="pathData" android:duration="400" android:valueFrom="M 9.5 15 C 10.881 15 12 13.881 12 12..." android:valueTo="M 9.49 14.6 C 10.607 14.6 11.99 13.481..." android:valueType="pathType" + AnimatedVectorDrawable API 21
  26. animation 10% android:name="calendar" android:pathData="M 9.5 15 C 10.881 15 12

    ..." android:fillColor="#ffffff" android:fillAlpha="0.7"/> </vector> </aapt:attr> <target android:name="calendar"> <aapt:attr name="android:animation"> <set> <objectAnimator android:propertyName="pathData" android:duration="400" android:valueFrom="M 9.5 15 C 10.881 15 12 13.881 12 12..." android:valueTo="M 9.49 14.6 C 10.607 14.6 11.99 13.481..." android:valueType="pathType" android:interpolator="@android:interpolator/fast_out_slow_in"/> <objectAnimator android:propertyName="pathData" android:startOffset="420" android:duration="150" android:valueFrom="M 9.49 14.6 C 10.607 14.6 11.99 13.4..." android:valueTo="M 9.5 15 C 10.881 15 12 13.881 12 12.5..." android:valueType="pathType" + AnimatedVectorDrawable API 21
  27. animation 10% <target android:name="calendar"> <aapt:attr name="android:animation"> <set> <objectAnimator android:propertyName="pathData" android:duration="400"

    android:valueFrom="M 9.5 15 C 10.881 15 12 13.881 12 12..." android:valueTo="M 9.49 14.6 C 10.607 14.6 11.99 13.481..." android:valueType="pathType" android:interpolator="@android:interpolator/fast_out_slow_in"/> <objectAnimator android:propertyName="pathData" android:startOffset="420" android:duration="150" android:valueFrom="M 9.49 14.6 C 10.607 14.6 11.99 13.4..." android:valueTo="M 9.5 15 C 10.881 15 12 13.881 12 12.5..." android:valueType="pathType" android:interpolator="@android:interpolator/fast_out_linear_in"/> <objectAnimator android:propertyName="pathData" android:startOffset="570" android:duration="150" + AnimatedVectorDrawable API 21
  28. animation 10% <target android:name="calendar"> <aapt:attr name="android:animation"> <set> <objectAnimator android:propertyName="pathData" android:duration="400"

    android:valueFrom="M 9.5 15 C 10.881 15 12 13.881 12 12..." android:valueTo="M 9.49 14.6 C 10.607 14.6 11.99 13.481..." android:valueType="pathType" android:interpolator="@android:interpolator/fast_out_slow_in"/> <objectAnimator android:propertyName="pathData" android:startOffset="420" android:duration="150" android:valueFrom="M 9.49 14.6 C 10.607 14.6 11.99 13.4..." android:valueTo="M 9.5 15 C 10.881 15 12 13.881 12 12.5..." android:valueType="pathType" android:interpolator="@android:interpolator/fast_out_linear_in"/> <objectAnimator android:propertyName="pathData" android:startOffset="570" android:duration="150" + AnimatedVectorDrawable API 21
  29. animation 10% android:interpolator="@android:interpolator/linear_out_slow_in"/> <objectAnimator android:propertyName="pathData" android:startOffset="750" android:duration="200" android:valueFrom="M 9.5 15.5

    C 11.318 15.5 12 14.081 12..." android:valueTo="M 9.5 15 C 10.881 15 12 13.881 12 12.5 ..." android:valueType="pathType" android:interpolator="@android:anim/overshoot_interpolator"/> <objectAnimator android:propertyName="fillAlpha" android:duration="300" android:valueFrom="0.7" android:valueTo="1" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in"/> </set> </aapt:attr> </target> </animated-vector> + AnimatedVectorDrawable API 21
  30. animation 10% + AnimatedVectorDrawable <com.google.android.material.bottomnavigation.BottomNavigationView ... app:menu="@menu/navigation" /> <!-- res/menu/navigation.xml

    --> <menu> <item android:id="@+id/navigation_schedule" android:icon="@drawable/asld_nav_schedule" android:title="Schedule" /> </menu> API 21
  31. data class HomeUiModel( val isChecked: Boolean ) button.checked = uiModel.isChecked

    Link: Motional Intelligence: Build Smarter Animations (Google I/O'19)
  32. animation 10% • ࠄޙ ୐ ߣ૩ ઴ • ࠄޙ ف

    ߣ૩ ઴ • ࠄޙ ࣁ ߣ૩ ઴ • ࠄޙ ֎ ߣ૩ ઴ • ࠄޙ ׮ࢽ ߣ૩ ઴ GradientDrawable class AnimatedGradientView : View() { private val colors = intArrayOf( Color.RED, Color.GREEN, Color.BLUE ) private val drawable = GradientDrawable( GradientDrawable.Orientation.BR_TL, colors.take(2).toIntArray() ) private val animator = createGradientAnimator() private fun createGradientAnimator(): Animator {
  33. animation 10% class AnimatedGradientView : View() { private val colors

    = intArrayOf( Color.RED, Color.GREEN, Color.BLUE ) private val drawable = GradientDrawable( GradientDrawable.Orientation.BR_TL, colors.take(2).toIntArray() ) private val animator = createGradientAnimator() private fun createGradientAnimator(): Animator { val max = colors.size return ValueAnimator.ofFloat(0f, max.toFloat()).apply { interpolator = LinearInterpolator() duration = 3_000L repeatCount = ValueAnimator.INFINITE GradientDrawable
  34. animation 10% ) private val drawable = GradientDrawable( GradientDrawable.Orientation.BR_TL, colors.take(2).toIntArray()

    ) private val animator = createGradientAnimator() private fun createGradientAnimator(): Animator { val max = colors.size return ValueAnimator.ofFloat(0f, max.toFloat()).apply { interpolator = LinearInterpolator() duration = 3_000L repeatCount = ValueAnimator.INFINITE repeatMode = ValueAnimator.RESTART val evaluator = ArgbEvaluator() addUpdateListener { val index = (it.animatedValue as Float).toInt() val start = colors[index % max] val center = colors[(index + 1) % max] val end = colors[(index + 2) % max] GradientDrawable
  35. animation 10% private fun createGradientAnimator(): Animator { val max =

    colors.size return ValueAnimator.ofFloat(0f, max.toFloat()).apply { interpolator = LinearInterpolator() duration = 3_000L repeatCount = ValueAnimator.INFINITE repeatMode = ValueAnimator.RESTART val evaluator = ArgbEvaluator() addUpdateListener { val index = (it.animatedValue as Float).toInt() val start = colors[index % max] val center = colors[(index + 1) % max] val end = colors[(index + 2) % max] val fraction = it.animatedValue as Float - index drawable.colors = intArrayOf( evaluator.evaluate(fraction, start, center) as Int, evaluator.evaluate(fraction, center, end) as Int ) } } } GradientDrawable
  36. animation 10% private fun createGradientAnimator(): Animator { val max =

    colors.size return ValueAnimator.ofFloat(0f, max.toFloat()).apply { interpolator = LinearInterpolator() duration = 3_000L repeatCount = ValueAnimator.INFINITE repeatMode = ValueAnimator.RESTART val evaluator = ArgbEvaluator() addUpdateListener { val index = (it.animatedValue as Float).toInt() val start = colors[index % max] val center = colors[(index + 1) % max] val end = colors[(index + 2) % max] val fraction = it.animatedValue as Float - index drawable.colors = intArrayOf( evaluator.evaluate(fraction, start, center) as Int, evaluator.evaluate(fraction, center, end) as Int ) } } } GradientDrawable API 16
  37. animation 10% drawable.colors = intArrayOf( evaluator.evaluate(fraction, start, center) as Int,

    evaluator.evaluate(fraction, center, end) as Int ) } } } init { background = drawable // Animation द੘ animator.start() // Animation ઺૑ animator.cancel() } } GradientDrawable API 16
  38. animation 10% view.clipToOutline = true view.outlineProvider = OvalOutlineProvider object OvalOutlineProvider

    : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { outline.setOval( view.paddingLeft, view.paddingTop, view.width - view.paddingRight, view.height - view.paddingBottom ) } } GradientDrawable API 21
  39. animation 10% view.clipToOutline = true view.outlineProvider = RoundRectOutlineProvider(clipRadius) class RoundRectOutlineProvider(

    private val radius: Float ) : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { outline.setRoundRect( view.paddingLeft, view.paddingTop, view.width - view.paddingRight, view.height - view.paddingBottom, radius ) } GradientDrawable API 21
  40. animation 10% class AnimatedBorderView : View() { private var borderWidth:

    Int = ... override fun draw(canvas: Canvas) { canvas.clipBorder(borderWidth) super.draw(canvas) } private fun Canvas.clipBorder(gap: Int) { val rect = Rect(gap, gap, width - gap, height - gap) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { clipOutRect(rect) } else { clipRect(rect, Region.Op.DIFFERENCE) GradientDrawable
  41. animation 10% private var borderWidth: Int = ... override fun

    draw(canvas: Canvas) { canvas.clipBorder(borderWidth) super.draw(canvas) } private fun Canvas.clipBorder(gap: Int) { val rect = Rect(gap, gap, width - gap, height - gap) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { clipOutRect(rect) } else { clipRect(rect, Region.Op.DIFFERENCE) } } } GradientDrawable
  42. animation 10% override fun draw(canvas: Canvas) { canvas.clipOuter(clipPath) super.draw(canvas) }

    private fun Canvas.clipOuter(path: Path) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { clipOutPath(path) } else { clipPath(path, Region.Op.DIFFERENCE) } } GradientDrawable
  43. animation 10% override fun draw(canvas: Canvas) { canvas.clipInner(clipPath) super.draw(canvas) }

    private fun Canvas.clipOuter(path: Path) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { clipPath(path) } else { clipPath(path, Region.Op.INTERSECT) } } GradientDrawable
  44. animation 10% • ٣੗੉ցо ખ ؊ ੗ਬ܂ѱ Ѿҗޛਸ ੘সೡ ࣻ

    ੓׮. • Android, iOS, Web ݽف زੌೞѱ ૑ਗೠ׮. • ױ, Vector ӝ߈੉޲۽ Gradationਸ ੸ਊೡ ࣻ হ׮. Render Adobe After Effects animations! Lottie Drawable Link: https://github.com/airbnb/lottie-android animation 10% 3rd Party
  45. animation 10% • PNGܳ ഛ੢ೠ ੉޷૑ ౵ੌ ನݘ (.png, .apng)

    • ৈ۞ ੢੄ PNG ੉޷૑ܳ ೞա۽ ೤ೠ ഋక׮. • Gradation ৈࠗী ࢚ҙহ੉ Animation оמೞ׮. • ױ, AnimationDrawable୊ۢ ݫݽܻ৬ FPS ޙઁо ੓׮. Animated Portable Network Graphics APNG Link: https://ko.wikipedia.org/wiki/APNG 3rd Party
  46. animation 10% • ImageView ١੄ Drawable APIী ࢎਊೡ ࣻ ੓׮.

    • ইऔѱب View ҳഅ୓ח ઁҕغ૑ ঋח׮. A lightweight and fast APNG image decoder for Android ApngDrawable Link: https://github.com/line/apng-drawable 3rd Party
  47. animation 10% ApngDrawable // WorkerThread val apngDrawable: ApngDrawable = ApngDrawable.decode(context.resources,

    resId).apply { loopCount = ApngDrawable.LOOP_FOREVER setTargetDensity(resources.displayMetrics) } // MainThread setImageDrawable(apngDrawable) 3rd Party
  48. animation 10% ProgressBar + RotateDrawable <layer-list> <item android:gravity="center"> <rotate android:drawable="@drawable/loading_custom_progress"

    android:pivotX="50%" android:pivotY="50%" android:fromDegrees="0" android:toDegrees="360" /> </item> <item android:drawable="@drawable/ic_android" android:gravity="center" /> </layer-list>
  49. animation 10% ProgressBar + RotateDrawable <layer-list> <item android:gravity="center"> <rotate android:drawable="@drawable/loading_custom_progress"

    android:pivotX="50%" android:pivotY="50%" android:fromDegrees="0" android:toDegrees="360" /> </item> <item android:drawable="@drawable/ic_android" android:gravity="center" /> </layer-list>
  50. animation 10% ProgressBar + RotateDrawable <layer-list> <item android:gravity="center"> <rotate android:drawable="@drawable/loading_custom_progress"

    android:pivotX="50%" android:pivotY="50%" android:fromDegrees="0" android:toDegrees="360" /> </item> <item android:drawable="@drawable/ic_android" android:gravity="center" /> </layer-list>
  51. animation 10% ProgressBar + RotateDrawable <layer-list> <item android:gravity="center"> <rotate android:drawable="@drawable/loading_custom_progress"

    android:pivotX="50%" android:pivotY="50%" android:fromDegrees="0" android:toDegrees="360" /> </item> <item android:drawable="@drawable/ic_android" android:gravity="center" /> </layer-list>
  52. animation 10% ProgressBar + ClipDrawable <layer-list> <item android:gravity="center_vertical" /> <item

    android:gravity="center_vertical"> <clip /> </item> </layer-list>
  53. animation 10% ProgressBar + ClipDrawable <layer-list> <item android:gravity="center_vertical"> <shape android:shape="rectangle">

    <corners android:radius="2dp" /> <size android:height="4dp" /> <solid android:color="#ebebeb" /> </shape> </item> <item android:gravity="center_vertical"> <clip /> </item> </layer-list>
  54. animation 10% ProgressBar + ClipDrawable <layer-list> <item android:gravity="center_vertical" /> <item

    android:gravity="center_vertical"> <clip android:clipOrientation="horizontal" android:gravity="start"> <shape android:shape="rectangle"> <corners android:radius="2dp" /> <size android:height="4dp" /> <gradient android:angle="180" android:endColor="@color/android4" android:startColor="@color/android1" /> </shape> </clip> </item>
  55. animation 10% • Drawable਷ Level ӝמ੉ ੓׮. (ߧਤ: 0 ~

    10000) • ClipDrawable, RotateDrawable, ScaleDrawable, LevelListDrawable ١ • Drawable#setLevel(int) API • ImageView#setImageLevel(int) API Drawableҗ Ѿ೤ೞৈ ࣚऔѱ Animation ҳഅ оמ Animator + Drawable Level
  56. animation 10% Animator + Drawable Level private val animator =

    ValueAnimator.ofFloat(0f, 1f).apply { repeatMode = ValueAnimator.REVERSE repeatCount = ValueAnimator.INFINITE duration = 1_000L interpolator = Interpolators.LINEAR addUpdateListener { batteryClip.setImageLevel( (it.animatedFraction * 10000).toInt()) } }
  57. animation 10% • XML ౵ੌ۽ ࢶ঱ೡ ࣻ ੓׮. • VSYNC৬

    োزೞৈ 60fps۽ ز੘ೠ׮. package android.animation Animator
  58. animation 10% AnimatorInflater Link: http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/ animation/AnimatorInflater.java#666 • res/animator/{file_name}.xml <set />

    <animator /> <objectAnimator /> <propertyValuesHolder /> -> AnimatorSet -> ValueAnimator -> ObjectAnimator -> PropertyValuesHolder[]
  59. animation 10% Animator abstract class Animator class AnimatorSet extends Animator

    class ValueAnimator extends Animator class ObjectAnimator extends ValueAnimator class TimeAnimator extends ValueAnimator
  60. animation 10% • ValueAnimatorо Choreographerܳ ੉ਊೠ׮. VSYNCܳ ੉ਊೞৈ, ٣झ೒ۨ੉ ೐ۨ੐

    ۪؊݂ झாેਸ ҙܻ Choreographer Link: https://developer.android.com/reference/android/view/Choreographer API 16
  61. animation 10% Choreographer val choreographer = Choreographer.getInstance() choreographer.postFrameCallback { //

    draw next frame } // Not this view.post() // But this view.postOnAnimation { ... } API 16
  62. animation 10% Choreographer val choreographer = Choreographer.getInstance() choreographer.postFrameCallback { //

    draw next frame } // Not this view.invalidate() // But this view.postInvalidateOnAnimation() API 16
  63. animation 10% public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {

    private void start(boolean playBackwards) { ... AnimationHandler.getInstance() .addAnimationFrameCallback(this, delay); ... } public final boolean doAnimationFrame(long frameTime) {} } public class AnimationHandler { Choreographer: Animator
  64. animation 10% private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {

    @Override public void doFrame(long frameTimeNanos) { doAnimationFrame(getProvider().getFrameTime()); Choreographer.getInstance() .postFrameCallback(mFrameCallback); } }; public void addAnimationFrameCallback(...) { Choreographer.getInstance() .postFrameCallback(mFrameCallback); } } Choreographer: Animator
  65. animation 10% ... } public final boolean doAnimationFrame(long frameTime) {}

    } public class AnimationHandler { private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { doAnimationFrame(getProvider().getFrameTime()); Choreographer.getInstance() .postFrameCallback(mFrameCallback); } }; public void addAnimationFrameCallback(...) { Choreographer.getInstance() .postFrameCallback(mFrameCallback); Choreographer: Animator
  66. animation 10% public final boolean doAnimationFrame(long frameTime) {} } public

    class AnimationHandler { private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { doAnimationFrame(getProvider().getFrameTime()); Choreographer.getInstance() .postFrameCallback(mFrameCallback); } }; public void addAnimationFrameCallback(...) { Choreographer.getInstance() .postFrameCallback(mFrameCallback); } } Choreographer: Animator
  67. animation 10% public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {

    private void start(boolean playBackwards) { ... AnimationHandler.getInstance() .addAnimationFrameCallback(this, delay); ... } public final boolean doAnimationFrame(long frameTime) {} } public class AnimationHandler { private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { doAnimationFrame(getProvider().getFrameTime()); Choreographer: Animator
  68. animation 10% Animator ValueAnimator.ofFloat(0f, 1f).apply { repeatMode = ValueAnimator.REVERSE repeatCount

    = ValueAnimator.INFINITE duration = 1_000L interpolator = Interpolators.ACCELERATE_DECELERATE }
  69. animation 10% <animator android:valueType="floatType" android:valueFrom="0" android:valueTo="1" android:repeatMode="reverse" android:repeatCount="infinite" android:duration="1000" android:interpolator=

    "@android:interpolator/accelerate_decelerate" /> Animator ValueAnimator.ofFloat() ValueAnimator.ofInt() ValueAnimator.ofPropertyValuesHolder() ValueAnimator.ofArgb()
  70. animation 10% Animator ValueAnimator.ofFloat(0f, 1f).apply { repeatMode = ValueAnimator.REVERSE repeatCount

    = ValueAnimator.INFINITE duration = 1_000L interpolator = Interpolators.ACCELERATE_DECELERATE }
  71. animation 10% val animator = ValueAnimator.ofFloat(0f, 1f).apply { repeatMode =

    ValueAnimator.REVERSE repeatCount = ValueAnimator.INFINITE duration = 1_000L interpolator = Interpolators.ACCELERATE_DECELERATE } Animator
  72. animation 10% val animator = ValueAnimator.ofFloat(0f, 1f).apply { repeatMode =

    ValueAnimator.REVERSE repeatCount = ValueAnimator.INFINITE duration = 1_000L interpolator = Interpolators.ACCELERATE_DECELERATE } animator.addUpdateListener { updateUi(it.animatedFraction) // or updateUi(it.animatedValue as Float) } animator.removeAllUpdateListeners() animator.start() animator.cancel() Animator
  73. animation 10% Animator private fun updateUi(fraction: Float) { iconView.run {

    rotation = lerp(0f, 360f, fraction) alpha = lerp(1f, .5f, fraction) scaleX = lerp(1f, 2f, fraction) scaleY = lerp(1f, .5f, fraction) translationX = lerp(0f, maxTranslationX, fraction) translationY = lerp(0f, maxTranslationY, fraction) } bugView.translationX = lerp(0f, maxTranslationX, fraction) }
  74. animation 10% Lerp fun lerp(from: Float, to: Float, progress: Float):

    Float { return from + (to - from) * progress }
  75. animation 10% <CoordinatorLayout> <AppBarLayout> <CollapsingConstraintLayout> <ImageView ... android:id="@+id/image" android:background="@drawable/user_icon" android:scaleType="centerCrop"

    /> <Alpha ... app:constraint_referenced_ids="image" /> </CollapsingConstraintLayout> </AppBarLayout> ... Lerp + ConstraintLayout
  76. animation 10% class CollapsingConstraintLayout : ConstraintLayout(), AppBarLayout.OnOffsetChangedListener { override fun

    onOffsetChanged(appBarLayout: AppBarLayout, verticalOffset: Int) { setProgress(-verticalOffset / appBarLayout.totalScrollRange.toFloat()) } private fun setProgress(progress: Float) { val fraction = progress.coerceIn(0f, 1f) children.forEach { if (it is ProgressHelper) { it.setProgress(fraction) } } } ... Lerp + ConstraintLayout
  77. animation 10% class Alpha : ConstraintHelper(), ProgressHelper { override fun

    setProgress(progress: Float) { ... views.forEach { it.alpha = lerp(0f, 1f, 1f - progress) } } ... Lerp + ConstraintLayout
  78. animation 10% LayoutTransition // ViewGroup.java case R.styleable.ViewGroup_animateLayoutChanges: boolean animateLayoutChanges =

    a.getBoolean(attr, false); if (animateLayoutChanges) { setLayoutTransition(new LayoutTransition()); } break; API 11
  79. animation 10% PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1); PropertyValuesHolder pvhTop

    = PropertyValuesHolder.ofInt("top", 0, 1); PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1); PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1); PropertyValuesHolder pvhScrollX = PropertyValuesHolder.ofInt("scrollX", 0, 1); PropertyValuesHolder pvhScrollY = PropertyValuesHolder.ofInt("scrollY", 0, 1); defaultChange = ObjectAnimator.ofPropertyValuesHolder((Object)null, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScrollX, pvhScrollY); defaultFadeIn = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f); defaultFadeOut = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f); LayoutTransition API 11
  80. animation 10% container.layoutTransition.apply { setInterpolator(LayoutTransition.APPEARING, Interpolators.ACCELERATE_DECELERATE) setDuration(LayoutTransition.APPEARING, 300) } //

    LayoutTransition.APPEARING // LayoutTransition.DISAPPEARING // LayoutTransition.CHANGE_APPEARING // LayoutTransition.CHANGE_DISAPPEARING // LayoutTransition.CHANGING LayoutTransition API 11
  81. animation 10% // Show revealView.showContents() private fun View.showContents() { visibility

    = View.VISIBLE createCircularRevealOf(fab, 0f, radius) { duration = 300 interpolator = Interpolators.DECELERATE }.start() } // Hide revealView.hideContents() private fun View.hideContents() { Circular Reveal API 21
  82. animation 10% createCircularRevealOf(fab, 0f, radius) { duration = 300 interpolator

    = Interpolators.DECELERATE }.start() } // Hide revealView.hideContents() private fun View.hideContents() { createCircularRevealOf(fab, radius, 0f) { duration = 300 interpolator = Interpolators.ACCELERATE doOnEnd { visibility = View.GONE } }.start() } private inline fun View.createCircularRevealOf( target: View, Circular Reveal API 21
  83. animation 10% doOnEnd { visibility = View.GONE } }.start() }

    private inline fun View.createCircularRevealOf( target: View, startRadius: Float, endRadius: Float, block: Animator.() -> Unit ): Animator { return ViewAnimationUtils.createCircularReveal( this, target.centerX(), target.centerY(), startRadius, endRadius ).apply(block) } Circular Reveal API 21
  84. animation 10% interface CircularRevealWidget class CircularRevealLinearLayout extends LinearLayout class CircularRevealRelativeLayout

    extends RelativeLayout class CircularRevealGridLayout extends GridLayout class CircularRevealFrameLayout extends FrameLayout class CircularRevealCoordinatorLayout extends CoordinatorLayout class CircularRevealCardView extends MaterialCardView MDC Circular Reveal API 14
  85. animation 10% private inline fun View.createCircularRevealOf( target: View, startRadius: Float,

    endRadius: Float, block: Animator.() -> Unit ): Animator { return ViewAnimationUtils.createCircularReveal( this, target.centerX(), target.centerY(), startRadius, endRadius ).apply(block) } Circular Reveal API 21
  86. animation 10% private inline fun CircularRevealWidget.createCircularRevealCompatOf( target: View, startRadius: Float,

    endRadius: Float, block: Animator.() -> Unit ): Animator { return CircularRevealCompat.createCircularReveal( this, target.centerX().toFloat(), target.centerY().toFloat(), startRadius, endRadius ).apply(block) } MDC Circular Reveal API 14
  87. animation 10% <View android:id="@+id/scrim" ... android:background="#66333333" android:visibility="invisible" app:layout_behavior= "@string/fab_transformation_scrim_behavior" />

    <com.google.android.material.circularreveal.cardview.CircularRevealCardView android:id="@+id/sheet" android:visibility="invisible" app:layout_behavior= "@string/fab_transformation_sheet_behavior"> ... </com.google.android.material.circularreveal.cardview.CircularRevealCardView> FAB Transform
  88. animation 10% <View android:id="@+id/scrim" ... android:background="#66333333" android:visibility="invisible" app:layout_behavior= "@string/fab_transformation_scrim_behavior" />

    <com.google.android.material.circularreveal.cardview.CircularRevealCardView android:id="@+id/sheet" android:visibility="invisible" app:layout_behavior= "@string/fab_transformation_sheet_behavior"> ... </com.google.android.material.circularreveal.cardview.CircularRevealCardView> FAB Transform
  89. animation 10% <!-- res/animator/sla_fab.xml --> <selector> <item android:state_pressed="true"> <objectAnimator android:duration="100"

    android:propertyName="translationZ" android:valueTo="6dp" android:valueType="floatType" /> </item> <item> <objectAnimator android:duration="100" android:propertyName="translationZ" android:valueTo="0dp" android:valueType="floatType" /> StateListAnimator
  90. animation 10% <!-- res/animator/sla_fab.xml --> <selector> <item android:state_pressed="true"> <objectAnimator android:duration="100"

    android:propertyName="translationZ" android:valueTo="6dp" android:valueType="floatType" /> </item> <item> <objectAnimator android:duration="100" android:propertyName="translationZ" android:valueTo="0dp" android:valueType="floatType" /> </item> </selector> StateListAnimator
  91. animation 10% <!-- res/animator/sla_fab.xml --> <selector> <item android:state_pressed="true"> <set> <objectAnimator

    /> <objectAnimator android:duration="100" android:propertyName="scaleX" android:valueTo="1.1" android:valueType="floatType" /> <objectAnimator android:duration="100" android:propertyName="scaleY" android:valueTo="1.1" android:valueType="floatType" /> StateListAnimator
  92. animation 10% <!-- res/animator/sla_card.xml --> <selector> <item android:state_activated="true"> <set android:ordering="together">

    <objectAnimator android:propertyName="backgroundColor" /> <objectAnimator android:propertyName="translationZ"/> </set> </item> <item> <set ... /> </item> </selector> StateListAnimator + Transition
  93. animation 10% <!-- res/animator/sla_card.xml --> <selector> <item android:state_activated="true"> <set android:ordering="together">

    <objectAnimator android:duration="200" android:propertyName="backgroundColor" android:valueFrom="@color/android1" android:valueTo="@color/android4" android:valueType="colorType" /> <objectAnimator /> </set> </item> <item> <set android:ordering="together"> StateListAnimator + Transition
  94. animation 10% android:valueFrom="@color/android1" android:valueTo="@color/android4" android:valueType="colorType" /> <objectAnimator /> </set> </item>

    <item> <set android:ordering="together"> <objectAnimator android:duration="200" android:propertyName="backgroundColor" android:valueFrom="@color/android4" android:valueTo="@color/android1" android:valueType="colorType" /> <objectAnimator /> </set> </item> </selector> StateListAnimator + Transition
  95. animation 10% <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/itemView" ... android:stateListAnimator="@animator/sla_card"> ... <androidx.constraintlayout.widget.Group android:id="@+id/actionGroup" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="gone" app:constraint_referenced_ids="add,close,touchApp" /> </androidx.constraintlayout.widget.ConstraintLayout> itemView.isActivated = expand StateListAnimator + Transition
  96. animation 10% • 0f, 1f ࢎ੉੄ чਸ ੸੺ೞѱ ࠁрػ чਵ۽

    ߈ജೠ׮. • ઺р੄ ч਷ 0f ~ 1f ߧਤܳ ߩযզ ࣻ ੓૑݅,
 द੘җ ՘਷ 0f, 1fܳ ࠁ੢ೠ׮. • ױࣽ൤ Inputী Outputਸ ߈ജೞח Ѫ੉޲۽,
 Singletonਵ۽ ࢎਊೡ ࣻ ੓׮. Animation੉ ߸ചೞח ੿ب Interpolator
  97. animation 10% Interpolator // package android.animation; public interface TimeInterpolator {

    // input : 0 and 1.0 // output: The interpolation value. float getInterpolation(float input); } // package android.view.animation; public interface Interpolator extends TimeInterpolator { }
  98. animation 10% Interpolator Link: android/view/animation/AnimationUtils.java#408 • res/interpolator/{file_name}.xml <linearInterpolator /> <accelerateInterpolator

    /> <decelerateInterpolator /> <accelerateDecelerateInterpolator /> <cycleInterpolator /> <anticipateInterpolator /> <overshootInterpolator /> <anticipateOvershootInterpolator /> <bounceInterpolator /> <pathInterpolator /> -> LinearInterpolator -> AccelerateInterpolator -> DecelerateInterpolator -> AccelerateDecelerateInterpolator -> CycleInterpolator -> AnticipateInterpolator -> OvershootInterpolator -> AnticipateOvershootInterpolator -> BounceInterpolator -> PathInterpolator
  99. animation 10% Interpolator AnimationUtils.loadInterpolator( context, android.R.interpolator.linear) val animation: Animation =

    ... animation.setInterpolator( context, android.R.interpolator.linear) <objectAnimator android:interpolator="@android:interpolator/linear" ... />
  100. animation 10% PathInterpolator android.view.animation <!-- Quad --> <pathInterpolator android:controlX1="0.33" android:controlY1="0"

    /> <!-- Cubic --> <pathInterpolator android:controlX1="0.33" android:controlY1="0" android:controlX2="1" android:controlY2="1" /> <!-- Path --> <pathInterpolator android:pathData="M 0.0,0.0 l 1.0,0.0 l 0.0,1.0" /> API 21
  101. animation 10% PathInterpolator android.view.animation // Quad PathInterpolator(0.33f, 0f) // Cubic

    PathInterpolator(0.33f, 0f, 1f, 1f) // Path PathInterpolator(Path().apply { moveTo(0f,0f) lineTo(1f, 0f) lineTo(0f, 1f) }) API 21
  102. animation 10% PathInterpolatorCompat androidx.core.view.animation // Quad PathInterpolatorCompat.create(0.33f, 0f) // Cubic

    PathInterpolatorCompat.create(0.33f, 0f, 1f, 1f) // Path PathInterpolatorCompat.create(Path().apply { moveTo(0f,0f) lineTo(1f, 0f) lineTo(0f, 1f) }) implementation 'androidx.interpolator:interpolator:1.0.0' API 14
  103. animation 10% Easing Interpolator val EASE_IN_OUT_CUBIC by cubicBezier(0.645f, 0.045f, 0.355f,

    1f)
 private fun cubicBezier( x1: Float, y1: Float, x2: Float, y2: Float ): Lazy<Interpolator> { return lazy { PathInterpolatorCompat.create(x1, y1, x2, y2) } }
  104. animation 10% • ೙ਃೠ ҃਋, Custom Viewী Attributeܳ ୶оೞৈ
 Layout

    XMLী Interpolatorܳ ࢶ঱ೞח ߑߨ੉ оמೞ׮. Interpolator Attribute
  105. animation 10% Interpolator Attribute <declare-styleable name="CustomView"> <attr name="interpolator" format="reference" />

    </declare-styleable> init { val a: TypedArray = ... val resId = a.getResourceId( R.styleable.CustomView_interpolator, 0) if (resId > 0) { ... = AnimationUtils.loadInterpolator(context, resId) } ... }
  106. animation 10% Render into off-screen buffers. View Layer (Hardware vs

    Software) Link: Android Graphics Performance (Google I/O '13) API 11
  107. animation 10% Hardware Layer API 11 view.setLayerType(View.LAYER_TYPE_HARDWARE, null) // do

    animate! Link: https://developer.android.com/guide/topics/graphics/hardware-accel#layers
  108. animation 10% Hardware Layer API 11 view.setLayerType(View.LAYER_TYPE_HARDWARE, null) // do

    animate! view.setLayerType(View.LAYER_TYPE_NONE, null) Link: https://developer.android.com/guide/topics/graphics/hardware-accel#layers
  109. animation 10% • Viewী Alphaܳ ࢎਊೞח ҃਋,
 Viewܳ ࢚ࣘ೧ࢲ falseܳ

    ߈ജೞח Ѫ੉ ࢿמী ਬܻೞ׮. • ױ, View ղࠗ ਃٜࣗ੉ Ҁ஖૑ ঋইঠ ৢ߄ܰѱ Ӓ۰૓׮. An optimization when alpha is set on a view. View#hasOverlappingRendering() Link: Hidden Cost of Transparency (100 Days of Google Dev) API 16
  110. animation 10% View#hasOverlappingRendering() <ConstraintLayout> <ImageView ... android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" android:src="@drawable/user_icon" />

    <ImageView ... android:layout_marginStart="40dp" android:layout_marginTop="40dp" android:src="@drawable/user_icon" /> </ConstraintLayout> API 16
  111. animation 10% View#hasOverlappingRendering() <ConstraintLayout> <ImageView ... android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" android:src="@drawable/user_icon" />

    <ImageView ... android:layout_marginStart="40dp" android:layout_marginTop="40dp" android:src="@drawable/user_icon" /> </ConstraintLayout> API 16
  112. animation 10% View#hasOverlappingRendering() <ConstraintLayout android:alpha="0.5"> <ImageView ... android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" android:src="@drawable/user_icon"

    /> <ImageView ... android:layout_marginStart="40dp" android:layout_marginTop="40dp" android:src="@drawable/user_icon" /> </ConstraintLayout> API 16
  113. animation 10% View#hasOverlappingRendering() <ConstraintLayout android:alpha="0.5"> <ImageView ... android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" android:src="@drawable/user_icon"

    /> <ImageView ... android:layout_marginStart="40dp" android:layout_marginTop="40dp" android:src="@drawable/user_icon" /> </ConstraintLayout> API 16
  114. animation 10% View#hasOverlappingRendering() <AlphaOptimizedConstraintLayout android:alpha="0.5"> <ImageView ... android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" android:src="@drawable/user_icon"

    /> <ImageView ... android:layout_marginStart="40dp" android:layout_marginTop="40dp" android:src="@drawable/user_icon" /> </AlphaOptimizedConstraintLayout> API 16
  115. animation 10% View#hasOverlappingRendering() <AlphaOptimizedConstraintLayout android:alpha="0.5"> <ImageView ... android:layout_marginEnd="40dp" android:layout_marginBottom="40dp" android:src="@drawable/user_icon"

    /> <ImageView ... android:layout_marginStart="40dp" android:layout_marginTop="40dp" android:src="@drawable/user_icon" /> </AlphaOptimizedConstraintLayout> API 16
  116. animation 10% View#hasOverlappingRendering() class AlphaOptimizedConstraintLayout @JvmOverloads constructor( context: Context, attrs:

    AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { override fun hasOverlappingRendering(): Boolean { return false } } Custom Link: AlphaOptimizedFrameLayout.java
  117. animation 10% RecyclerView.ItemAnimator class SlideInUpAnimator : DefaultItemAnimator() { override fun

    animateAddImpl(holder: RecyclerView.ViewHolder) { holder.itemView.animate() .translationY(0f) .alpha(1f) .setDuration(addDuration) .start() } }
  118. animation 10% RecyclerView.ItemAnimator class RecyclerViewAdapter() : ListAdapter<Item, ViewHolder>( IdBasedDiffCallback {

    id.toString() } ) { ... } class IdBasedDiffCallback<T>( private val id: T.() -> String ) : DiffUtil.ItemCallback<T>() { override fun areItemsTheSame(oldItem: T, newItem: T): Boolean { return oldItem.id() == newItem.id() } ... }
  119. animation 10% • ViewPropertyAnimator৬ ਬࢎೞ׮. • Windowр Animationী ࢎਊೡ ࣻ

    ੓׮. • Activity <—> Activity • Fragment <—> Fragment package android.view.animation View Animation
  120. animation 10% View Animation <set> <alpha android:fromAlpha="1.0" android:toAlpha="0.5" /> <translate

    android:fromXDelta="0" android:toXDelta="100" android:fromYDelta="0" android:toYDelta="100" /> </set>
  121. animation 10% View Animation <set android:shareInterpolator="true" android:duration="1000" android:interpolator="@android:anim/accelerate_interpolator"> <alpha android:fromAlpha="1.0"

    android:toAlpha="0.5" /> <translate android:fromXDelta="0" android:toXDelta="100" android:fromYDelta="0" android:toYDelta="100" /> </set>
  122. animation 10% Window Animation: Activity activity.overridePendingTransition( R.anim.slide_in_right, // enterAnim R.anim.slide_out_left

    // exitAnim ) activity.overridePendingTransition( R.anim.slide_in_left, // popEnterAnim R.anim.slide_out_right // popExitAnim )
  123. animation 10% Window Animation: Fragment fragmentManager.beginTransaction() .setCustomAnimations( R.anim.slide_in_right, // enterAnim

    R.anim.slide_out_left, // exitAnim R.anim.slide_in_left, // popEnterAnim R.anim.slide_out_right // popExitAnim ) .replace(...) .commit()
  124. animation 10% DynamicAnimation.ViewProperty ViewProperty TRANSLATION_X = new ViewProperty("translationX") ViewProperty TRANSLATION_Y

    = new ViewProperty("translationY") ViewProperty TRANSLATION_Z = new ViewProperty("translationZ") ViewProperty SCALE_X = new ViewProperty("scaleX") ViewProperty SCALE_Y = new ViewProperty("scaleY") ViewProperty ROTATION = new ViewProperty("rotation") ViewProperty ROTATION_X = new ViewProperty("rotationX") ViewProperty ROTATION_Y = new ViewProperty("rotationY") ViewProperty X = new ViewProperty("x") ViewProperty Y = new ViewProperty("y") ViewProperty Z = new ViewProperty("z") ViewProperty ALPHA = new ViewProperty("alpha") ViewProperty SCROLL_X = new ViewProperty("scrollX") ViewProperty SCROLL_Y = new ViewProperty("scrollY")
  125. animation 10% SpringAnimation val spring = SpringAnimation( view, DynamicAnimation.TRANSLATION_X, 300f)

    .withSpringForceProperties { dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY stiffness = SpringForce.STIFFNESS_LOW } spring.start()
  126. animation 10% SpringAnimation val spring = SpringAnimation( view, DynamicAnimation.TRANSLATION_X, 300f)

    .withSpringForceProperties { dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY stiffness = SpringForce.STIFFNESS_LOW } spring.start()
  127. animation 10% SpringAnimation val spring = SpringAnimation( view, DynamicAnimation.TRANSLATION_X) .withSpringForceProperties

    { dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY stiffness = SpringForce.STIFFNESS_LOW } spring.animateToFinalPosition(300f)
  128. animation 10% SpringAnimation val spring = SpringAnimation( view, DynamicAnimation.TRANSLATION_X) .withSpringForceProperties

    { dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY stiffness = SpringForce.STIFFNESS_LOW } spring.animateToFinalPosition(300f) spring.animateToFinalPosition(0f)
  129. animation 10% SpringAnimation val spring = SpringAnimation( view, DynamicAnimation.TRANSLATION_X) .withSpringForceProperties

    { dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY stiffness = SpringForce.STIFFNESS_LOW } spring.animateToFinalPosition(300f) spring.animateToFinalPosition(0f) spring.animateToFinalPosition(500f)
  130. animation 10% fun View.spring( property: ViewProperty, stiffness: Float = 500f,

    damping: Float = SpringForce.DAMPING_RATIO_NO_BOUNCY, startVelocity: Float? = null ): SpringAnimation { val key = getKey(property) var springAnim = getTag(key) as? SpringAnimation? if (springAnim == null) { springAnim = SpringAnimation(this, property) setTag(key, springAnim) } springAnim.spring = (springAnim.spring ?: SpringForce()).apply { this.dampingRatio = damping this.stiffness = stiffness SpringAnimation
  131. animation 10% fun View.spring( property: ViewProperty, stiffness: Float = 500f,

    damping: Float = SpringForce.DAMPING_RATIO_NO_BOUNCY, startVelocity: Float? = null ): SpringAnimation { val key = getKey(property) var springAnim = getTag(key) as? SpringAnimation? if (springAnim == null) { springAnim = SpringAnimation(this, property) setTag(key, springAnim) } springAnim.spring = (springAnim.spring ?: SpringForce()).apply { this.dampingRatio = damping this.stiffness = stiffness } startVelocity?.let { springAnim.setStartVelocity(it) } return springAnim } SpringAnimation
  132. animation 10% stiffness: Float = 500f, damping: Float = SpringForce.DAMPING_RATIO_NO_BOUNCY,

    startVelocity: Float? = null ): SpringAnimation { val key = getKey(property) var springAnim = getTag(key) as? SpringAnimation? if (springAnim == null) { springAnim = SpringAnimation(this, property) setTag(key, springAnim) } springAnim.spring = (springAnim.spring ?: SpringForce()).apply { this.dampingRatio = damping this.stiffness = stiffness } startVelocity?.let { springAnim.setStartVelocity(it) } return springAnim } SpringAnimation Link: https://github.com/android/plaid/.../SpringUtils.kt#L31
  133. animation 10% class SpringItemAnimator : DefaultItemAnimator() { override fun animateMove(...):

    Boolean { val view = holder.itemView val fromX = fromViewX + holder.itemView.translationX.toInt() val fromY = fromViewY + holder.itemView.translationY.toInt() endAnimation(holder) val deltaX = toViewX - fromX val deltaY = toViewY - fromY ... if (deltaX != 0) { view.translationX = (-deltaX).toFloat() } if (deltaY != 0) { view.translationY = (-deltaY).toFloat() } SpringItemAnimator
  134. animation 10% override fun animateMove(...): Boolean { val view =

    holder.itemView val fromX = fromViewX + holder.itemView.translationX.toInt() val fromY = fromViewY + holder.itemView.translationY.toInt() endAnimation(holder) val deltaX = toViewX - fromX val deltaY = toViewY - fromY ... if (deltaX != 0) { view.translationX = (-deltaX).toFloat() } if (deltaY != 0) { view.translationY = (-deltaY).toFloat() } pendingMoves.add(holder) return true } override fun runPendingAnimations() { super.runPendingAnimations() SpringItemAnimator
  135. animation 10% if (deltaY != 0) { view.translationY = (-deltaY).toFloat()

    } pendingMoves.add(holder) return true } override fun runPendingAnimations() { super.runPendingAnimations() ... if (pendingMoves.isNotEmpty()) { for (i in pendingMoves.indices.reversed()) { moveItem(pendingMoves.removeAt(i)) } } } private fun moveItem(holder: RecyclerView.ViewHolder) { val springX = holder.itemView.spring(TRANSLATION_X) val springY = holder.itemView.spring(TRANSLATION_Y) ... SpringItemAnimator
  136. animation 10% if (pendingMoves.isNotEmpty()) { for (i in pendingMoves.indices.reversed()) {

    moveItem(pendingMoves.removeAt(i)) } } } private fun moveItem(holder: RecyclerView.ViewHolder) { val springX = holder.itemView.spring(TRANSLATION_X) val springY = holder.itemView.spring(TRANSLATION_Y) ... springX.animateToFinalPosition(0f) springY.animateToFinalPosition(0f) ... } } SpringItemAnimator Link: https://github.com/android/plaid/.../SlideInItemAnimator.kt
  137. animation 10% Transition <!-- res/transition/auto_transition.xml --> <autoTransition /> val transition

    = TransitionInflater.from(it.context) .inflateTransition(R.transition.auto_transition) TransitionManager.beginDelayedTransition(container, transition) outerBackground.visibility = View.VISIBLE innerBackground.visibility = View.VISIBLE
  138. animation 10% TransitionInflater Link: http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/ transition/TransitionInflater.java#148 • res/transition/{file_name}.xml <autoTransition />

    <fade /> <changeBounds /> <slide /> <explode /> <changeImageTransform /> <changeTransform /> <changeClipBounds /> <transitionSet /> ... -> AutoTransition -> Fade -> ChangeBounds -> Slide -> Explode -> ChangeImageTransform -> ChangeTransform -> ChangeClipBounds -> TransitionSet ...
  139. animation 10% • TransitionValuesח View ё୓৬ View IDী ӝ߈ೞৈ ஭୊ػ׮.

    Transition public abstract class Transition { public abstract void captureStartValues( TransitionValues transitionValues); public abstract void captureEndValues( TransitionValues transitionValues); protected void animate(Animator animator) { ... } }
  140. animation 10% Shared Elements // Between activities val activityOptions =

    ActivityOptionsCompat.makeSceneTransitionAnimation( activity, Pair.create(view, view.transitionName) ) ActivityCompat.startActivity(context, intent, activityOptions.toBundle()) // Between fragments fragmentManager.beginTransaction() .addSharedElement(view, view.transitionName) .replace(...) .setReorderingAllowed(true) .commit()
  141. animation 10% Shared Elements // Between activities val activityOptions =

    ActivityOptionsCompat.makeSceneTransitionAnimation( activity, Pair.create(view, view.transitionName) ) ActivityCompat.startActivity(context, intent, activityOptions.toBundle()) // Between fragments fragmentManager.beginTransaction() .addSharedElement(view, view.transitionName) .replace(...) .setReorderingAllowed(true) .commit()
  142. animation 10% Shared Elements: Navigation // Navigation: Between activities val

    extras = ActivityNavigatorExtras( ActivityOptionsCompat.makeSceneTransitionAnimation( activity, Pair.create(view, view.transitionName) ) ) findNavController().navigate(actionToDetail(), extras) // Navigation: Between fragments val extras = FragmentNavigatorExtras( view to view.transitionName ) findNavController().navigate(actionToDetail(), extras)
  143. animation 10% Shared Elements // In Kotlin view.transitionName = context.getString(R.string.transition_name)

    <!-- In XML --> <View android:id="@+id/view" ... android:transitionName="@string/transition_name" />
  144. animation 10% Shared Elements <!-- res/transition/move_shared_element.xml --> <transitionSet> <changeBounds />

    <targets> <target android:targetId="@id/view" /> </targets> </transitionSet>
  145. animation 10% Shared Elements <!-- res/transition/move_shared_element.xml --> <transitionSet> <changeBounds />

    <arcMotion /> <targets> <target android:targetId="@id/view" /> </targets> </transitionSet>
  146. animation 10% Shared Elements class MasterFragment : Fragment() class DetailFragment

    : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedElementEnterTransition = ...(R.transition.move_shared_element) sharedElementReturnTransition = ...(R.transition.move_shared_element) } }
  147. animation 10% Shared Elements class MasterFragment : Fragment() class DetailFragment

    : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedElementEnterTransition = ...(R.transition.move_shared_element) sharedElementReturnTransition = ...(R.transition.move_shared_element) } }
  148. animation 10% Shared Elements class MasterFragment : Fragment() { override

    fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) exitTransition = ...(R.transition.move) reenterTransition = ...(R.transition.move) } } class DetailFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enterTransition = ...(R.transition.move) returnTransition = ...(R.transition.move) sharedElementEnterTransition = ...(R.transition.move_shared_element) sharedElementReturnTransition = ...(R.transition.move_shared_element) } }
  149. animation 10% Shared Elements <!-- res/transition/move.xml --> <transitionSet> <explode />

    <changeBounds> <targets> <target android:excludeId="@id/view" /> </targets> </changeBounds> </transitionSet>
  150. animation 10% Shared Elements <!-- res/transition/move.xml --> <transitionSet> <explode> <targets>

    <target android:excludeId="@id/appBar" /> </targets> </explode> <changeBounds> <targets> <target android:excludeId="@id/view" /> </targets> </changeBounds> </transitionSet>
  151. animation 10% Shared Elements <!-- res/transition/move.xml --> <transitionSet android:transitionOrdering="sequential"> <explode>

    <targets> <target android:excludeId="@id/appBar" /> </targets> </explode> <changeBounds> <targets> <target android:excludeId="@id/view" /> </targets> </changeBounds> </transitionSet>
  152. animation 10% • ߸ചೞח ੉޷૑ • Drawable Animation • CustomView

    + Animator
 • ਑૒੉ח ױੌ ੉޷૑ • ViewPropertyAnimator • DynamicAnimation Summary Link: https://github.com/fornewid/android-animation-10p-more • ೣԋ ਑૒੉ח ੉޷૑ٜ • Animator (+ lerp) • Transition
 • ചݶ ੹ജ • View Animation • Transition (+ SharedElements)
  153. animation 10% Q & A A N D R O

    I D animation +10%