SlideShare a Scribd company logo
The world of
Android Animations
+Nelson Glauber
@nglauber
www.nglauber.com.br
Por que animações?
Animations!
• No mundo real coisas não aparecem “do nada”, elas
se movimentam
• O olho humano é sensível ao movimento e isso
pode ajudar o usuário a entender melhor seu
aplicativo
• Pense na sua aplicação como um palco onde a
informação entra e sai do palco de maneira
coordenada.
https://developer.android.com/design/get-started/principles.html
The world of Android Animations
1ª geração de
animações
View Animations
<alpha
android:duration="1000"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
val alphaAnim = AnimationUtils.loadAnimation(

context, R.anim.my_animation);
imageView.startAnimation(anim);
val alphaAnim = AlphaAnimation(1f, 0f)
alphaAnim.duration = 1000
imageView.startAnimation(alphaAnim)
res/anim/my_animation.xml
val anim = RotateAnimation(
0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f)
anim.duration = 1000
imageView.startAnimation(anim)
<rotate
android:duration="1000"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%" />
val anim = ScaleAnimation(1, 3, 1, 3,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f)
anim.duration = 1000
myView.startAnimation(anim)
<scale
android:duration="1000"
android:fromXScale="1.0"
android:toXScale="3.0"
android:fromYScale="1.0"
android:toYScale="3.0"
android:pivotX="50%"
android:pivotY="50%" />
Não corte sua animação!
<ViewGroup
...
android:clipChildren="false"
android:clipToPadding="false" />
val anim = TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, 1.0f,
Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, 2.0f)
anim.duration = 1000
myView.startAnimation(anim)
<translate
android:duration="1000"
android:fromXDelta="0"
android:toXDelta="100%"
android:fromYDelta="0"
android:toYDelta="200%" />
Combinando animações
val animationSet = AnimationSet(true)
animationSet.addAnimation(rotate)
animationSet.addAnimation(alpha)
animationSet.addAnimation(scale)
animationSet.addAnimation(translate)
animationSet.setDuration(1000)
myView.startAnimation(animationSet)
<set android:duration="1000">
<rotate ... />
<alpha ... />
<scale ... />
<translate ... />
</set>
val interpolator = …
LinearInterpolator()
AccelerateDecelerateInterpolator()
BounceInterpolator()
AccelerateInterpolator(1.0f) // factor (optional)
AnticipateInterpolator(2.0f) // <- tension (optional)
// tension, extra tension (optional)
AnticipateOvershootInterpolator(2.0f, 1.5f)
CycleInterpolator(2f) // <- cycles
DecelerateInterpolator(1.0f) // <- factor (optional)
OvershootInterpolator(2.0f) // <- tension (optional)
FastOutLinearInInterpolator()

FastOutSlowInInterpolator()

LinearOutSlowInInterpolator()
anim.interpolator = interpolator
<translate ...
android:interpolator="@android:anim/overshoot_interpolator"/>
Interpolator class Resource ID
LinearInterpolator @android:anim/linear_interpolator
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator
BounceInterpolator @android:anim/bounce_interpolator
AccelerateInterpolator @android:anim/accelerate_interpolator
AnticipateInterpolator @android:anim/anticipate_interpolator
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator
DecelerateInterpolator @android:anim/decelerate_interpolator
OvershootInterpolator @android:anim/overshoot_interpolator
FastOutLinearInInterpolator	 @interpolator/fast_out_linear_in	(support)	
FastOutSlowInInterpolator	 @interpolator/fast_out_slow_in	(support)	
LinearOutSlowInInterpolator	 @interpolator/linear_out_slow_in	(suppport)
val anim = // Qualquer animação…
anim.setAnimationListener(object : AnimationListener {
override fun onAnimationStart(animation: Animation) {
}
override fun onAnimationRepeat(animation: Animation) {
}
override fun onAnimationEnd(animation: Animation) {
}
})
anim.fillBefore = false
anim.fillAfter = true
anim.repeatCount = 1
anim.repeatMode = Animation.REVERSE // INFINITE or RESTART
myView.startAnimation(anim)
Animando a mudança de Activity
Animando a mudança de Activity
val it = Intent(this, NewActivity::class.java)
startActivity(it)
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim)
override fun onBackPressed() {
super.onBackPressed()
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim)
}
Animação quadro-a-quadro
<animation-list ...
android:oneshot="false">
<item android:drawable=“@drawable/mario_0"
android:duration="100" />
<item android:drawable=“@drawable/mario_1"
android:duration="100" />
<item android:drawable=“@drawable/mario_2"
android:duration="100" />
...
</animation-list>
res/drawable/sprite.xml
Imagem: https://rawgit.com/Grafluxe/sequence-runner/master/sample/index.html
Animação quadro-a-quadro
val sprite = … // ImageView
sprite.setBackgroundResource(R.drawable.sprite)
val spriteAnimation = sprite.background as AnimationDrawable
if (spriteAnimation.isRunning){
spriteAnimation.stop()
} else {
spriteAnimation.start()
}
Imagem: https://rawgit.com/Grafluxe/sequence-runner/master/sample/index.html
Prós e contras…
• Prós
• Simples de usar
• Disponível em todas as versões do Android
• Contras
• Muito limitado
• Não altera a posição real da view 😱
2ª geração de
animações
View Property
Animator
Property Animations
• Disponível a partir do Android 3.0 (v11)
• Simples e fácil de usar
• Você pode animar várias propriedades usando
simplesmente o método animate() da view (v12).
view.animate()
.alpha(0)
.translationX(-view.getHeight())
.translationY(-view.getWidth())
.scaleX(2f)
.scaleY(2f)
.rotation(360)
.setInterpolator(LinearInterpolator())
.withStartAction(Runnable {
// animation's started
})
.withEndAction(Runnable {
// animation's finished
})
.setDuration(1000)
.setStartDelay(1000)
.start()
Property Animations
Animator
AnimatorSet ValueAnimator
ObjectAnimator
Podemos animar qualquer
propriedade utilizando as classes:
val alpha = ObjectAnimator.ofFloat(view, View.ALPHA, 0f)
alpha.repeatMode = ValueAnimator.REVERSE
alpha.repeatCount = 1
val animXml = AnimatorInflater.loadAnimator(
this, R.animator.anim_fade)
animXml.setTarget(imgBazinga)
res/animator/anim_fade.xml
<objectAnimator xmlns:android="..."
android:duration="1000"
android:propertyName="alpha"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
val scaleX = ObjectAnimator.ofFloat(
view, View.SCALE_X, 2f)
val scaleY = ObjectAnimator.ofFloat(
view, View.SCALE_Y, 2f)
val transl = ObjectAnimator.ofFloat(
view, View.TRANSLATION_X, -view.getWidth())
val rotate = ObjectAnimator.ofFloat(
view, View.ROTATION, 360f)
val alpha = ObjectAnimator.ofFloat(
view, View.ALPHA, 0f)
val animatorSet = AnimatorSet()
animatorSet.play(scaleX)
.with(scaleY)
.with(transl)
animatorSet.play(rotate)
.with(alpha)
.after(transl)
animatorSet.duration = 2000
animatorSet.start()
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(2000);
// Sequentially
animatorSet.playSequentially(
scaleX, scaleY, transl, rotate, alpha);
// or Together
animatorSet.playTogether(
scaleX, scaleY, transl, rotate, alpha);
animatorSet.start();
<set xmlns:android=“…”
android:ordering="together">
<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="1"
android:valueTo="2"
android:valueType="floatType" />
<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="1"
android:valueTo="2"
android:valueType="floatType" />
</set>
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationCancel(animation: Animator) {
super.onAnimationCancel(animation)
}
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
}
override fun onAnimationRepeat(animation: Animator) {
super.onAnimationRepeat(animation)
}
override fun onAnimationStart(animation: Animator) {
super.onAnimationStart(animation)
}
override fun onAnimationPause(animation: Animator) {
super.onAnimationPause(animation)
}
override fun onAnimationResume(animation: Animator) {
super.onAnimationResume(animation)
}
})
Property Animations
<<interface>>

TypeEvaluator<T>
IntEvaluator
ArgbEvaluator
FloatEvaluator
Podemos utilizar os evaluators existentes
para calcular o valores das propriedades:
ObjectAnimator.ofObject(textView,
"textColor",
ArgbEvaluator(),
textView.currentTextColor,
Color.RED).start()
Animate Layout changes
<LinearLayout
...
android:animateLayoutChanges="true" />
API Level 11
3ª geração de
animações
The world of Android Animations
Scenes & Transitions
• Introduzida no Android 4.4. KitKat (API Level 19)
• Captura o estado de cada view da cena e anima
para o estado da próxima cena
The world of Android Animations
val sceneMore = Scene.getSceneForLayout(
sceneRoot, R.layout.scene_more, context)
val sceneLess = Scene.getSceneForLayout(
sceneRoot, R.layout.scene_less, context)
TransitionManager.go(if (more) sceneMore else sceneLess,
AutoTransition())
// reset views and events 😢
Transitions
• From API 19
• Fade
• AutoTransition
• ChangeBounds
• TransitionSet
• From API 21
• Slide
• Explode
• ChangeClipBounds
• ChangeImageTransform
• ChangeTransform
The world of Android Animations
val transitionSet = TransitionSet()
transitionSet.ordering = TransitionSet.ORDERING_SEQUENTIAL
transitionSet.addTransition(Slide(Gravity.RIGHT))
transitionSet.addTransition(ChangeBounds())
TransitionManager.beginDelayedTransition(
constraintLayout, transitionSet)
val visibility = if (fieldsVisible) View.VISIBLE else View.GONE
txtNome.visibility = visibility
edtNome.visibility = visibility
txtIdade.visibility = visibility
edtIdade.visibility = visibility
<transitionSet xmlns:android=“…”
android:transitionOrdering=“sequential">
<slide android:slideEdge="right"/>
<changeBounds />
</transitionSet>
val transition = TransitionInflater.from(this)
.inflateTransition(R.transition.transition_form)
TransitionManager.beginDelayedTransition(
constraintLayout, transition)
animation.addListener(object : Transition.TransitionListener {
override fun onTransitionEnd(transition: Transition?) {
}
override fun onTransitionResume(transition: Transition?) {
}
override fun onTransitionPause(transition: Transition?) {
}
override fun onTransitionCancel(transition: Transition?) {
}
override fun onTransitionStart(transition: Transition?) {
}
})
Custom Transition
class CircleViewProgressTransition(context: Context, attrs: AttributeSet)
: Transition(context, attrs) {
override fun captureStartValues(transitionValues: TransitionValues) {
captureValues(transitionValues)
}
override fun captureEndValues(transitionValues: TransitionValues) {
captureValues(transitionValues)
}
private fun captureValues(transitionValues: TransitionValues) {
if (transitionValues.view is CircleView) {
val circleView = transitionValues.view as CircleView
transitionValues.values.put(PROPNAME_ANGLE, circleView.getAngle())
}
}
...
companion object {
private val PROPNAME_ANGLE = "myapp.ui.view:CircleView:angle"
}
}
Custom Transition
override fun createAnimator(sceneRoot: ViewGroup, startValues: TransitionValues?,
endValues: TransitionValues?): Animator? {
if (startValues != null && endValues != null && endValues.view is CircleView) {
val circleView = endValues.view as CircleView
val startAngle = startValues.values[PROPNAME_ANGLE] as Float
val endAngle = endValues.values[PROPNAME_ANGLE] as Float
if (startAngle != endAngle) {
circleView.setAngle(startAngle)
val animCircleProgress = ObjectAnimator.ofFloat(
circleView, CircleView.ANGLE, endAngle)
animCircleProgress.setInterpolator(AccelerateDecelerateInterpolator())
animCircleProgress.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
circleView.setAngle(endAngle)
}
})
return animCircleProgress
}
}
return null
}
android.support.transition
• O Google fornece uma biblioteca de suporte para
v14+
• Mas apenas um subconjunto está disponível:
• AutoTransition, ChangeBounds, Fade,
TransitionSet
• Scene e TransitionManager
• TransitionInflater NÃO está disponível.
4ª geração
Activity & Fragment
Transitions
Activity & Fragment Transitions
• Disponível a partir do Android 5 (API 21)
• Maneira melhor de coreografar animações entre
activities/fragments
• Content transitions permitem especificar como as
views saem e entram na tela
• Shared element transition são elementos presentes
em ambas as telas onde podemos fazer uma
transição mais suave
The world of Android Animations
Window Transitions
<style name="MyCustomTheme" parent="AppTheme">
<item name="android:windowExitTransition">@transition/exit</item>
<item name="android:windowEnterTransition">@transition/enter</item>
<item name="android:windowReenterTransition">@transition/reenter</item>
<item name="android:windowReturnTransition">@transition/return</item>
...
</style>
window.exitTransition = transition
window.enterTransition = transition
window.reenterTransition = transition
window.returnTransition = transition
<explode xmlns:android=“…”/>
res/transition-v21/list_exit.xml
<style name="ListDiscosTheme" parent="AppTheme">
<item name="android:windowExitTransition">@transition/list_exit</item>
<item name="android:windowReenterTransition">@transition/list_exit</item>
</style>
res/values-v21/styles.xml
val it = Intent(this, DetailAlbumActivity::class.java)
it.putExtra(DetailAlbumActivity.EXTRA_DISCO, Parcels.wrap(disco))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val options = ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
startActivity(it, options)
} else {
startActivity(it)
}
val it = Intent(this, DetailAlbumActivity::class.java)
it.putExtra(DetailAlbumActivity.EXTRA_DISCO, Parcels.wrap(disco))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val options = ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
startActivity(it, options)
} else {
startActivity(it)
}
override fun onCreate(savedInstanceState: Bundle?) {
setupWindowAnimations()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list_albums)
// ...
}
private fun setupWindowAnimations() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val transition = Explode()
window.exitTransition = transition
window.reenterTransition = transition
}
}
Shared Element Transition
<style name="ListDiscosTheme" parent="AppTheme">
<item name=“android:windowSharedElementExitTransition">
@transition/shd_exit
</item>
<item name=“android:windowSharedElementEnterTransition">
@transition/shd_enter
</item>
<item name=“android:windowSharedElementReenterTransition">
@transition/shd_reenter
</item>
<item name=“android:windowSharedElementReturnTransition">
@transition/shd_return
</item>
...
</style>
window.sharedElementExitTransition = transition
window.sharedElementEnterTransition = transition
window.sharedElementReenterTransition = transition
window.sharedElementReturnTransition = transition
Shared Element Transition
val it = Intent(this, DetailAlbumActivity::class.java)
it.putExtra(DetailAlbumActivity.EXTRA_DISCO, Parcels.wrap(disco))
val options = ActivityOptions.makeSceneTransitionAnimation(
this,
Pair(view.findViewById(R.id.imgCapa), "capa"),
Pair(view.findViewById(R.id.txtTitulo), "titulo"),
Pair(view.findViewById(R.id.txtAno), "ano")
).toBundle()
startActivity(it, options)
<style name="ListDiscosTheme" parent="AppTheme">
...
<item name="android:windowContentTransitions">true</item>
</style>
ViewCompat.setTransitionName(imgCapa, "capa")
ViewCompat.setTransitionName(txtTitulo, "titulo")
ViewCompat.setTransitionName(txtAno, "ano")
res/values-v21/styles.xml
ListAlbumsActivity
DetailAlbumActivity
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
Shared Element Transition em Fragments
ChangeBounds changeBoundsTransition = TransitionInflater.from(this)
.inflateTransition(R.transition.change_bounds);
fragmentB.setSharedElementEnterTransition(changeBoundsTransition);
getFragmentManager().beginTransaction()
.replace(R.id.content, fragmentB)
.addSharedElement(blueView, getString(R.string.blue_name))
.commit();
Reveal animation
The world of Android Animations
val transition = AutoTransition()
transition.duration = resources.getInteger(
android.R.integer.config_mediumAnimTime).toLong()
transition.pathMotion = GravityArcMotion()
val constraintSet = ConstraintSet()
constraintSet.clone(constraintlayout)
TransitionManager.beginDelayedTransition(constraintlayout, transition)
constraintSet.clear(R.id.fabAdd, ConstraintSet.BOTTOM)
constraintSet.clear(R.id.fabAdd, ConstraintSet.RIGHT)
constraintSet.connect(R.id.fabAdd, ConstraintSet.TOP,
R.id.cardViewCity, ConstraintSet.TOP)
constraintSet.connect(R.id.fabAdd, ConstraintSet.LEFT,
R.id.cardViewCity, ConstraintSet.LEFT)
constraintSet.connect(R.id.fabAdd, ConstraintSet.BOTTOM,
R.id.cardViewCity, ConstraintSet.BOTTOM)
constraintSet.connect(R.id.fabAdd, ConstraintSet.RIGHT,
R.id.cardViewCity, ConstraintSet.RIGHT)
constraintSet.applyTo(constraintlayout)
https://github.com/nickbutcher/plaid/blob/master/app/src/main/java/io/plaidapp/ui/transitions/GravityArcMotion.java
val cx = (cardViewCity.left + cardViewCity.right) / 2
val cy = (cardViewCity.top + cardViewCity.bottom) / 2
val anim = ViewAnimationUtils.createCircularReveal(
cardViewCity, cx, cy, fabAdd.width.toFloat(), cardViewCity.width.toFloat())
cardViewCity.visibility = View.VISIBLE
anim.start()
val cx = (cardViewCity.left + cardViewCity.right) / 2
val cy = (cardViewCity.top + cardViewCity.bottom) / 2
val anim = ViewAnimationUtils.createCircularReveal(
cardViewCity, cx, cy, cardViewCity.width.toFloat(), fabAdd.width.toFloat())
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
cardViewCity.visibility = View.INVISIBLE
}
})
}
anim.start()
The world of Android Animations
<style name="RevealActivityMain" parent="AppTheme">
<item name="android:windowContentTransitions">true</item>
</style>
val options = ActivityOptionsCompat
.makeSceneTransitionAnimation(this, Pair(fabAdd, "circular"))
.toBundle()
startActivity(Intent(this, RevealDetailActivity::class.java), options)
<autoTransition xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_longAnimTime">
<arcMotion
android:maximumAngle="90"
android:minimumHorizontalAngle="15"
android:minimumVerticalAngle="0" />
</autoTransition>
<style name="RevealActivityDetail" parent="AppTheme">
<item name="android:windowContentTransitions">true</item>
<item name=“android:windowSharedElementEnterTransition">
@transition/transition_activity_reveal
</item>
</style>
ViewCompat.setTransitionName(viewPlaceHolder, "circular")
if (isLollipopOrLater() && savedInstanceState == null) {
viewTop.visibility = View.INVISIBLE
window.sharedElementEnterTransition.addListener(
object: TransitionListenerAdapter() {
override fun onTransitionEnd(transition: Transition?) {
super.onTransitionEnd(transition)
circularRevealActivity()
}
})
}
Animated Vector
Drawable
AnimatedVectorDrawable
• Um vector drawable é composto por uma série
padronizada de comandos chamada de path.
• É possível criar um group desses comandos.
• Um animated vector drawable nos permite animar
parte de um vector drawable.
The world of Android Animations
companion object {
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
}
}
android {
...
defaultConfig {
...
vectorDrawables.useSupportLibrary true
}
Path (Comandos)
• M x,y

começa um novo subpath movendo para x,y
• L x,y

desenha uma linha para x,y
• C x1,y1 x2,y2 x,y

desenha uma curva de Bezier cúbica para x,y usando os
pontos de controle x1,y1 e x2,y2
• Z

Fecha um path desenhando uma linha reta de volta ao
ponto de origem do subpath atual
L3,10 L6,8
L6,4
M3,2 Z
M6,4
L6,8
L9,6
L6,4Z
M3,2
L3,10
L5,10
L5,2
Z M7,2
L7,10
L9,10
L9,2
Z
<string name="path_play_1">M 3,2 L 3,10 L 6,8 L 6,4 Z</string>
<string name="path_play_2">M 6,4 L 6,8 L 9,6 L 6,4 Z</string>
res/values/strings.xml
<string name="path_pause_1">M 3,2 L 3,10 L 5,10 L 5,2 Z</string>
<string name="path_pause_2">M 7,2 L 7,10 L 9,10 L 9,2 Z</string>
res/values/strings.xml
drawable
values
drawable-v21
values-v21
ic_vector_play.xml
ic_vector_pause.xml
ic_avd_pause_play.xml
ic_avd_play_pause.xml
refs.xml
refs.xml
Vector Drawables
Animated

Vector Drawables
Referência de acordo
com a versão
<vector xmlns:android="..."
android:width="48dp"
android:height="48dp"
android:viewportHeight="12"
android:viewportWidth="12">
<group
android:name="triangle"
android:pivotX="6"
android:pivotY="6">
<path
android:name="triangle_1"
android:fillColor="#FFFFFF"
android:pathData="@string/path_play_1" />
<path
android:name="triangle_2"
android:fillColor="#FFFFFF"
android:pathData="@string/path_play_2" />
</group>
</vector>
ic_vector_play.xml
<vector xmlns:android="..."
android:width="48dp"
android:height="48dp"
android:viewportHeight="12"
android:viewportWidth="12">
<path
android:name="bar_1"
android:fillColor="#FFFFFF"
android:pathData="@string/path_pause_1" />
<path
android:name="bar_2"
android:fillColor="#FFFFFF"
android:pathData="@string/path_pause_2" />
</vector>
ic_vector_pause.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_vector_play">
<target android:name="triangle">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="300"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="180"
android:valueType="floatType" />
</aapt:attr>
</target>
<target android:name="triangle_1">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="300"
android:propertyName="pathData"
android:valueFrom="@string/path_play_1"
android:valueTo="@string/path_pause_1"
android:valueType="pathType" />
</aapt:attr>
</target>
<target android:name="triangle_2">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="300"
android:propertyName="pathData"
android:valueFrom="@string/path_play_2"
android:valueTo="@string/path_pause_2"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>
ic_avd_play_pause.xml
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_vector_pause">
<target android:name="bar_1">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="300"
android:propertyName="pathData"
android:valueFrom="@string/path_pause_1"
android:valueTo="@string/path_play_1"
android:valueType="pathType" />
</aapt:attr>
</target>
<target android:name="bar_2">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="300"
android:propertyName="pathData"
android:valueFrom="@string/path_pause_2"
android:valueTo="@string/path_play_2"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>
ic_avd_pause_play.xml
<resources>
<item name="ic_play" type="drawable">@drawable/ic_vector_play</item>
<item name="ic_pause" type="drawable">@drawable/ic_vector_pause</item>
</resources>
<resources>
<item name="ic_play" type="drawable">@drawable/ic_avd_play_pause</item>
<item name="ic_pause" type=“drawable">@drawable/ic_avd_pause_play</item>
</resources>
<ImageView
...
app:srcCompat="@drawable/ic_play" />
values
values-v21
refs.xml
refs.xml
fun getIconDrawable(): Drawable? {
val drawableId: Int
if (isPlaying) {
drawableId = R.drawable.ic_play
} else {
drawableId = R.drawable.ic_pause
}
return ResourcesCompat.getDrawable(resources, drawableId, theme)
}
private fun togglePlayPause() {
isPlaying = !isPlaying
imageAnimatedVector.setImageDrawable(getIconDrawable())
animateButton(imageAnimatedVector.drawable)
}
private fun animateButton(icon: Drawable?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
icon is AnimatedVectorDrawable) {
icon.start()
}
}
https://romannurik.github.io/AndroidIconAnimator/
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="56dp"
android:height="56dp"
android:tint="?attr/colorControlNormal"
android:viewportHeight="56"
android:viewportWidth="56">
<path
android:pathData="@string/heart_stroke_left"
android:strokeColor="@android:color/white"
android:strokeWidth="2"/>
<path
android:pathData="@string/heart_stroke_right"
android:strokeColor="@android:color/white"
android:strokeWidth="2"/>
</vector>
res/drawable/ic_vector_heart_empty.xml
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="56dp"
android:height="56dp"
android:tint="?attr/colorControlNormal"
android:viewportHeight="56"
android:viewportWidth="56">
<!-- mesmos paths do fill -->
<group android:name="filled">
<clip-path
android:name="clip"
android:pathData="@string/heart_clip_shown"/>
<path
android:fillColor="@android:color/white"
android:pathData="@string/heart_full_path"/>
</group>
</vector>
res/drawable/ic_vector_heart_full.xml
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_vector_heart_full">
<target android:name="clip">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="pathData"
android:valueFrom="@string/heart_clip_shown"
android:valueTo="@string/heart_clip_hidden"
android:valueType="pathType"/>
</aapt:attr>
</target>
</animated-vector>
res/drawable-v21/ic_avd_heart_full_empty.xml
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_vector_heart_full">
<target android:name="clip">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="pathData"
android:valueFrom="@string/heart_clip_hidden"
android:valueTo="@string/heart_clip_shown"
android:valueType="pathType"/>
</aapt:attr>
</target>
</animated-vector>
res/drawable-v21/ic_avd_heart_empty_full.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/liked"
android:drawable="@drawable/ic_vector_heart_full"
android:state_checked="true"/>
<item
android:id="@+id/not_liked"
android:drawable="@drawable/ic_vector_heart_empty"/>
</selector>
drawable/selector_heart.xml
<animated-selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/liked"
android:drawable="@drawable/ic_vector_heart_full"
android:state_checked="true" />
<item
android:id="@+id/not_liked"
android:drawable="@drawable/ic_vector_heart_empty" />
<transition
android:drawable="@drawable/ic_avd_heart_empty_full"
android:fromId="@id/not_liked"
android:toId="@id/liked" />
<transition
android:drawable="@drawable/ic_avd_heart_full_empty"
android:fromId="@id/liked"
android:toId="@id/not_liked" />
</animated-selector>
drawable-v21/selector_heart.xml
Physics-based
animation
https://developer.android.com/guide/topics/graphics/spring-animation.html
https://gist.github.com/nickbutcher/7fdce476aaa589680cdd626d78e3149d
E aquela animação, que
gira, pula, solta fogos…🤔
https://github.com/airbnb/lottie-android
The world of Android Animations
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/animation_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:lottie_fileName="assetSubDir/spring.json"
app:lottie_loop="true"
app:lottie_autoPlay="true" />
LottieAnimationView animationView = (LottieAnimationView)
findViewById(R.id.animation_view);
animationView.setAnimation("assetSubDir/spring.json");
animationView.loop(true);
animationView.playAnimation();
dependencies {
compile 'com.airbnb.android:lottie:2.0.0-beta4'
}
Algumas libs…
• https://github.com/andkulikov/Transitions-Everywhere
• https://github.com/willowtreeapps/spruce-android
• https://github.com/glomadrian/Grav
• https://github.com/daimajia/AndroidViewAnimations
• https://github.com/2359media/
EasyAndroidAnimations
• http://facebook.github.io/rebound/
Referências
• Material Design para Desenvolvedores Android

https://br.udacity.com/course/material-design-for-android-developers--ud862/
• Andre Mion Animations

https://stories.uplabs.com/music-player-3a85864d6df7

https://blog.prototypr.io/applying-meaningful-motion-on-android-
a271a873bd78
• Plaid (Nick Butcher)

https://github.com/nickbutcher/plaid
• Animatable (Nick Butcher)

https://goo.gl/99Y9qD
Referências
• Android transitions with examples

https://github.com/lgvalle/Material-Animations
• An Introduction to Icon Animation Techniques

http://www.androiddesignpatterns.com/2016/11/introduction-to-icon-
animation-techniques.html
• Animate all the things. Transitions in Android

https://medium.com/@andkulikov/animate-all-the-things-transitions-in-
android-914af5477d50
• Animate me, If you don't do it for me do it for Chet :)

https://pt.slideshare.net/Android2EE/animate-me-if-you-dont-do-it-for-me-do-
it-for-chet
Dúvidas?
@nglauber
+NelsonGlauber
www.nglauber.com.br

More Related Content

PDF
Animações Fluídas no Android - DevFestPR 17
ODP
Android App Development - 12 animations
PPTX
Android Training (Animation)
PPTX
Android animation theory
PDF
Enhancing UI/UX using Java animations
PPTX
Animations avec Compose : rendez vos apps chat-oyantes
DOCX
Android view animation in android-chapter18
PPTX
Animate me, If you don't do it for me do it for Chet :)
Animações Fluídas no Android - DevFestPR 17
Android App Development - 12 animations
Android Training (Animation)
Android animation theory
Enhancing UI/UX using Java animations
Animations avec Compose : rendez vos apps chat-oyantes
Android view animation in android-chapter18
Animate me, If you don't do it for me do it for Chet :)

Similar to The world of Android Animations (20)

PPTX
Basic Android Animation
DOCX
Android animation and color state list resources-chapter 10
PPTX
Android animations
PPTX
Animation in android
PDF
[Android] Android Animation
PPTX
Android 3
PDF
Android animation
ODP
Day seven
PDF
Georgiy Shur: Bring onboarding to life
PDF
Breathing the life into the canvas
PDF
Beauty Treatment for your Android Application
DOCX
Android animation in android-chapter17
PPTX
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
PDF
Stop running from animations droidcon London
PPTX
Animation
PPTX
Material Design Android
PDF
Android 2D Drawing and Animation Framework
PPTX
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
PDF
Android ui tips & tricks
PDF
Tips & Tricks to spice up your Android app
Basic Android Animation
Android animation and color state list resources-chapter 10
Android animations
Animation in android
[Android] Android Animation
Android 3
Android animation
Day seven
Georgiy Shur: Bring onboarding to life
Breathing the life into the canvas
Beauty Treatment for your Android Application
Android animation in android-chapter17
Animate Me, if you don't do it for me do it for chet (DroidCon Paris)
Stop running from animations droidcon London
Animation
Material Design Android
Android 2D Drawing and Animation Framework
Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015
Android ui tips & tricks
Tips & Tricks to spice up your Android app
Ad

More from Nelson Glauber Leal (20)

PDF
Insights no desenvolvimento Android para 2024
PDF
Seu primeiro app Android e iOS com Compose Multiplatform
PDF
Desenvolvimento Moderno de Aplicações Android 2023
PDF
Novidades incríveis do Android em 2023
PDF
Novidades das Bibliotecas Jetpack do Android (2021)
PDF
Android Jetpack Compose - Turkey 2021
PDF
Jetpack Compose a new way to implement UI on Android
PDF
Jetpack Compose a nova forma de implementar UI no Android
PDF
Aplicações assíncronas no Android com
Coroutines & Jetpack
PDF
Aplicações assíncronas no Android com
Coroutines & Jetpack
PDF
O que é preciso para ser um desenvolvedor Android
PDF
Arquitetando seu app Android com Jetpack
PDF
Arquitetando seu app Android com Jetpack
PDF
Aplicações Assíncronas no Android com Coroutines e Jetpack
PDF
Mastering Kotlin Standard Library
PDF
Aplicações assíncronas no Android com Coroutines & Jetpack
PDF
Introdução ao Desenvolvimento Android com Kotlin
PDF
Persisting Data on SQLite using Room
PDF
Arquitetando seu aplicativo Android com Jetpack
PDF
Desenvolvimento Moderno de Aplicativos Android
Insights no desenvolvimento Android para 2024
Seu primeiro app Android e iOS com Compose Multiplatform
Desenvolvimento Moderno de Aplicações Android 2023
Novidades incríveis do Android em 2023
Novidades das Bibliotecas Jetpack do Android (2021)
Android Jetpack Compose - Turkey 2021
Jetpack Compose a new way to implement UI on Android
Jetpack Compose a nova forma de implementar UI no Android
Aplicações assíncronas no Android com
Coroutines & Jetpack
Aplicações assíncronas no Android com
Coroutines & Jetpack
O que é preciso para ser um desenvolvedor Android
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Aplicações Assíncronas no Android com Coroutines e Jetpack
Mastering Kotlin Standard Library
Aplicações assíncronas no Android com Coroutines & Jetpack
Introdução ao Desenvolvimento Android com Kotlin
Persisting Data on SQLite using Room
Arquitetando seu aplicativo Android com Jetpack
Desenvolvimento Moderno de Aplicativos Android
Ad

Recently uploaded (6)

PPTX
Introduction to Packet Tracer Course Overview - Aug 21 (1).pptx
PDF
Lesson 13- HEREDITY _ pedSAWEREGFVCXZDSASEWFigree.pdf
PDF
6-UseCfgfhgfhgfhgfhgfhfhhaseActivity.pdf
DOC
Camb毕业证学历认证,格罗斯泰斯特主教大学毕业证仿冒文凭毕业证
DOC
证书学历UoA毕业证,澳大利亚中汇学院毕业证国外大学毕业证
PPTX
ASMS Telecommunication company Profile
Introduction to Packet Tracer Course Overview - Aug 21 (1).pptx
Lesson 13- HEREDITY _ pedSAWEREGFVCXZDSASEWFigree.pdf
6-UseCfgfhgfhgfhgfhgfhfhhaseActivity.pdf
Camb毕业证学历认证,格罗斯泰斯特主教大学毕业证仿冒文凭毕业证
证书学历UoA毕业证,澳大利亚中汇学院毕业证国外大学毕业证
ASMS Telecommunication company Profile

The world of Android Animations