Slide 1

Slide 1 text

RecyclerView.ItemAnimator @MoyuruAizawa

Slide 2

Slide 2 text

MoyuruAizawa Moyuru Aizawa
 Software Engineer of Azit Inc. and RABO Inc. Previously at CyberAgent Inc. and Eureka Inc.

Slide 3

Slide 3 text

RecyclerViewγϦʔζ☺

Slide 4

Slide 4 text

‣ RecyclerView.LayoutManager ‣ RecyclerView.ItemDecoration ‣ RecyclerView.RecycledViewPool ‣ RecyclerView.ItemAnimator ‣ https://speakerdeck.com/lvla RecyclerViewγϦʔζ☺

Slide 5

Slide 5 text

‣ RecyclerView.Adapterʹมߋ͕ੜͨ࣌͡ͷΞχϝʔγϣϯΛఆٛ͢Δ ‣ ௥Ճ ‣ ࡟আ ‣ Ҡಈ ‣ มߋ ‣ Predictive Animations RecyclerView.ItemAnimator

Slide 6

Slide 6 text

‣ RecyclerView.ItemAnimatorΛܧঝͨ͠ந৅Ϋϥε ‣ ࢖͍·Θͤͦ͏ͳॲཧΛ༧Ί࣮૷ͯ͘͠ΕͯΔ ‣ 2ݸؔ਺Λ࣮૷͢Ε͹ͱΓ͋͑ͣ͸Ξχϝʔγϣϯͤ͞ΕΔ SimpleItemAnimator

Slide 7

Slide 7 text

‣ SimpleItemAnimator#animateXxx [Add | Remove | Move | Change] ‣ SimpleItemAnimator#runPendingAnimations ‣ SimpleItemAnimator#isRunning ‣ SimpleItemAnimator#endAnimation ‣ SimpleItemAnimator#endAnimations SimpleItemAnimator

Slide 8

Slide 8 text

‣ SimpleItemAnimator#animateXxx [Add | Remove | Move | Change] ‣ SimpleItemAnimator#runPendingAnimations ‣ SimpleItemAnimator#isRunning ‣ SimpleItemAnimator#endAnimation ‣ SimpleItemAnimator#endAnimations SimpleItemAnimator

Slide 9

Slide 9 text

‣ ࣮ߦ͍ͨ͠ΞχϝʔγϣϯΛఆٛ͢Δؔ਺ ‣ ͜ͷؔ਺಺Ͱ͸ΞχϝʔγϣϯΛ࣮ߦ͠ͳ͍ ‣ animateAddͰfade in͍ͤͨ͞৔߹ ‣ ViewͷalphaΛ0ʹ͓ͯ͘͠ ‣ alphaΛ0->1ʹ͢ΔAnimationΛ૊Έཱ͓ͯͯ͘ SimpleItemAnimator#animateXxx

Slide 10

Slide 10 text

‣ SimpleItemAnimator#animateXxxͰఆٛͨ͠ΞχϝʔγϣϯΛ࣮ߦ͢ Δؔ਺ SimpleItemAnimator#runPendingAnimations

Slide 11

Slide 11 text

‣ Ξχϝʔγϣϯத͔Ͳ͏͔ฦ͢ SimpleItemAnimator#isRunning

Slide 12

Slide 12 text

‣ ΞχϝʔγϣϯΛଈ࠲ʹऴྃ͢΂͖ͱ͖ʹݺ͹ΕΔ ‣ εΫϩʔϧͳͲͷΠϕϯτ࣌ʹݺ͹ΕΔ ‣ Fade inΞχϝʔγϣϯͷ৔߹ ‣ ΞχϝʔγϣϯΛΩϟϯηϧ͢Δ ‣ alphaΛ1ʹมߋ͢Δ SimpleItemAnimator#endAnimation / endAnimations

Slide 13

Slide 13 text

class Animator : SimpleItemAnimator() { private val pendingAnimators = LinkedList() private val runningAnimators = LinkedList() … override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean { holder.itemView.alpha = 0f ViewCompat.animate(holder.itemView) .alpha(1f) .setDuration(addDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateAdd

Slide 14

Slide 14 text

class Animator : SimpleItemAnimator() { private val pendingAnimators = LinkedList() private val runningAnimators = LinkedList() … override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean { holder.itemView.alpha = 0f ViewCompat.animate(holder.itemView) .alpha(1f) .setDuration(addDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateAdd

Slide 15

Slide 15 text

class Animator : SimpleItemAnimator() { private val pendingAnimators = LinkedList() private val runningAnimators = LinkedList() … override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean { holder.itemView.alpha = 0f ViewCompat.animate(holder.itemView) .alpha(1f) .setDuration(addDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateAdd

Slide 16

Slide 16 text

class Animator : SimpleItemAnimator() { private val pendingAnimators = LinkedList() private val runningAnimators = LinkedList() … override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean { holder.itemView.alpha = 0f ViewCompat.animate(holder.itemView) .alpha(1f) .setDuration(addDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateAdd

Slide 17

Slide 17 text

class Animator : SimpleItemAnimator() { … override fun runPendingAnimations() { pendingAnimators.forEach { animation -> animation.setListener(object : ViewPropertyAnimatorListener { override fun onAnimationStart(view: View?) { runningAnimators.add(animation) } override fun onAnimationEnd(view: View?) { runningAnimators.remove(animation) } override fun onAnimationCancel(view: View?) { runningAnimators.remove(animation) } }).start() pendingAnimators.clear() } } } SimpleItemAnimator#pendingAnimations

Slide 18

Slide 18 text

class Animator : SimpleItemAnimator() { … override fun runPendingAnimations() { pendingAnimators.forEach { animation -> animation.setListener(object : ViewPropertyAnimatorListener { override fun onAnimationStart(view: View?) { runningAnimators.add(animation) } override fun onAnimationEnd(view: View?) { runningAnimators.remove(animation) } override fun onAnimationCancel(view: View?) { runningAnimators.remove(animation) } }).start() pendingAnimators.clear() } } } SimpleItemAnimator#pendingAnimations

Slide 19

Slide 19 text

class Animator : SimpleItemAnimator() { … override fun runPendingAnimations() { pendingAnimators.forEach { animation -> animation.setListener(object : ViewPropertyAnimatorListener { override fun onAnimationStart(view: View?) { runningAnimators.add(animation) } override fun onAnimationEnd(view: View?) { runningAnimators.remove(animation) } override fun onAnimationCancel(view: View?) { runningAnimators.remove(animation) } }).start() pendingAnimators.clear() } } } SimpleItemAnimator#pendingAnimations

Slide 20

Slide 20 text

class Animator : SimpleItemAnimator() { … override fun runPendingAnimations() { pendingAnimators.forEach { animation -> animation.setListener(object : ViewPropertyAnimatorListener { override fun onAnimationStart(view: View?) { runningAnimators.add(animation) } override fun onAnimationEnd(view: View?) { runningAnimators.remove(animation) } override fun onAnimationCancel(view: View?) { runningAnimators.remove(animation) } }).start() pendingAnimators.clear() } } } SimpleItemAnimator#pendingAnimations

Slide 21

Slide 21 text

class Animator : SimpleItemAnimator() { … override fun runPendingAnimations() { pendingAnimators.forEach { animation -> animation.setListener(object : ViewPropertyAnimatorListener { override fun onAnimationStart(view: View?) { runningAnimators.add(animation) } override fun onAnimationEnd(view: View?) { runningAnimators.remove(animation) } override fun onAnimationCancel(view: View?) { runningAnimators.remove(animation) } }).start() pendingAnimators.clear() } } } SimpleItemAnimator#pendingAnimations

Slide 22

Slide 22 text

class Animator : SimpleItemAnimator() { private val runningAnimators = LinkedList() override fun isRunning() = runningAnimators.isNotEmpty() override fun endAnimation(item: RecyclerView.ViewHolder) { item.itemView.animation?.cancel() item.itemView.alpha = 1f } … } SimpleItemAnimator#isRunning, endAnimation

Slide 23

Slide 23 text

Predictive Animations Predictive Animations Predictive Animations

Slide 24

Slide 24 text

‣ ૿ݮ͢ΔΞΠςϜͷΞχϝʔγϣϯʹ߹ΘͤͯલޙͷΞΠςϜͷҐஔ Λௐ੔͢Δ ‣ LayoutManager͕Predictive AnimationsʹରԠ͍ͯ͠Δඞཁ͕͋Δ
 (LinearLayoutManager, GridLayoutManager…) ‣ SimpleItemAnimator͸Predictive Animationsͷ࣮૷΋؆୯ ‣ SimpleItemAnimator#animateMoveΛ࣮૷͢Δ͚ͩ Predictive Animations

Slide 25

Slide 25 text

class Animator : SimpleItemAnimator() { … override fun animateMove( holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int ): Boolean { holder.itemView.y = fromY.toFloat() ViewCompat.animate(holder.itemView) .y(toY.toFloat()) .setDuration(moveDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateMove

Slide 26

Slide 26 text

class Animator : SimpleItemAnimator() { … override fun animateMove( holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int ): Boolean { holder.itemView.y = fromY.toFloat() ViewCompat.animate(holder.itemView) .y(toY.toFloat()) .setDuration(moveDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateMove

Slide 27

Slide 27 text

class Animator : SimpleItemAnimator() { … override fun animateMove( holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int ): Boolean { holder.itemView.y = fromY.toFloat() ViewCompat.animate(holder.itemView) .y(toY.toFloat()) .setDuration(moveDuration) .setInterpolator(DecelerateInterpolator()) .let(pendingAnimators::add) return true } } SimpleItemAnimator#animateMove

Slide 28

Slide 28 text

Thank You