SlideShare a Scribd company logo
1 of 83
Download to read offline
squeezing precious milliseconds
Native Android animations
Animating values
val animator = ObjectAnimator.ofInt(0, 100)
Animating values
val animator = ObjectAnimator.ofInt(0, 100)
animator.duration = 1000
Animating values
val animator = ObjectAnimator.ofInt(0, 100)
animator.duration = 1000
animator.interpolator = FastOutSlowInInterpolator()
Animating values
val animator = ObjectAnimator.ofInt(0, 100)
animator.duration = 1000
animator.interpolator = FastOutSlowInInterpolator()
animator.addUpdateListener { Log.d("pasha", "${it.animatedValue}") }1
Animating values
val animator = ObjectAnimator.ofInt(0, 100)
animator.duration = 1000
animator.interpolator = FastOutSlowInInterpolator()
animator.addUpdateListener { Log.d("pasha", "${it.animatedValue}") }1
animator.start()
Animating values
val animator = ObjectAnimator.ofInt(0, 100)
animator.apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener { Log.d("pasha", "${it.animatedValue}") }1
start()
}2
Animating values
Animating view properties
Animating view properties
Animating view properties
val animator = ObjectAnimator.ofFloat(1f, 1.5f)
animator.apply {
duration = 1000
interpolator = OvershootInterpolator()
addUpdateListener {
view.scaleX = it.animatedValue
view.scaleY = it.animatedValue
}1
start()
}2
Animating view properties
val animator = ObjectAnimator.ofFloat(1f, 1.5f)
animator.apply {
duration = 1000
interpolator = OvershootInterpolator()
addUpdateListener {
view.scaleX = it.animatedValue
view.scaleY = it.animatedValue
}1
start()
}2
Animating view properties
val animator = ObjectAnimator.ofFloat(1f, 1.5f)
animator.apply {
duration = 1000
interpolator = OvershootInterpolator()
addUpdateListener {
view.scaleX = it.animatedValue
view.scaleY = it.animatedValue
}1
start()
}2
Animating view properties
val animator = ObjectAnimator.ofFloat(1f, 1.5f)
animator.apply {
duration = 1000
interpolator = OvershootInterpolator()
addUpdateListener {
view.scaleX = it.animatedValue
view.scaleY = it.animatedValue
}1
start()
}2
Animating view properties
view.animate()
.scaleX(1.5f)
.scaleY(1.5f)
.setDuration(1000)
.setInterpolator(OvershootInterpolator())
.start()
Animating view properties
view.animate()
.scaleX(1.5f)
.scaleY(1.5f)
.setDuration(1000)
.setInterpolator(OvershootInterpolator())
.start()
Animating view properties
view.animate()
.scaleX(1.5f)
.scaleY(1.5f)
.setDuration(1000)
.setInterpolator(OvershootInterpolator())
.start()
Animating view properties
• scale
view.animate()
.scaleX(1.5f)
.scaleY(1.5f)
.setDuration(1000)
.setInterpolator(OvershootInterpolator())
.start()
Animating view properties
• scale
• alpha
view.animate()
.scaleX(1.5f)
.scaleY(1.5f)
.setDuration(1000)
.setInterpolator(OvershootInterpolator())
.start()
Animating view properties
• scale
• alpha
• translation
view.animate()
.scaleX(1.5f)
.scaleY(1.5f)
.setDuration(1000)
.setInterpolator(OvershootInterpolator())
.start()
Animating view properties
• scale
• alpha
• translation
• rotation
Changing view properties does
not trigger measure/layout pass
Animate LayoutParams!
private fun expand(view: View) {
}3
Animate LayoutParams!
private fun expand(view: View) {
val oldHeight = view.measuredHeight
val newHeight = oldHeight + 300
}3
Animate LayoutParams!
private fun expand(view: View) {
val oldHeight = view.measuredHeight
val newHeight = oldHeight + 300
ObjectAnimator.ofInt(oldHeight, newHeight).apply {
}2
}3
Animate LayoutParams!
private fun expand(view: View) {
val oldHeight = view.measuredHeight
val newHeight = oldHeight + 300
ObjectAnimator.ofInt(oldHeight, newHeight).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
}2
}3
Animate LayoutParams!
private fun expand(view: View) {
val oldHeight = view.measuredHeight
val newHeight = oldHeight + 300
ObjectAnimator.ofInt(oldHeight, newHeight).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
view.layoutParams.height = it.animatedValue
}1
start()
}2
}3
Animate LayoutParams!
private fun expand(view: View) {
val oldHeight = view.measuredHeight
val newHeight = oldHeight + 300
ObjectAnimator.ofInt(oldHeight, newHeight).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
view.layoutParams.height = it.animatedValue
view.requestLayout()
}1
start()
}2
}3
Animate LayoutParams!
private fun expand(view: View) {
val oldHeight = view.measuredHeight
val newHeight = oldHeight + 300
ObjectAnimator.ofInt(oldHeight, newHeight).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
view.layoutParams.height = it.animatedValue
view.requestLayout()
}1
start()
}2
}3
Animate LayoutParams!
{16
ms
{16
ms
frames
Avoiding layouts
val oldHeight = textView.measuredHeight
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
val clipRect = Rect()
clipRect.right = root.measuredWidth
clipRect.bottom = root.measuredHeight - sizeChange
root.clipBounds = clipRect
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
val clipRect = Rect()
clipRect.right = root.measuredWidth
clipRect.bottom = root.measuredHeight - sizeChange
root.clipBounds = clipRect
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
val clipRect = Rect()
clipRect.right = root.measuredWidth
clipRect.bottom = root.measuredHeight - sizeChange
root.clipBounds = clipRect
ObjectAnimator
.ofFloat(-sizeChange, 0f)
.addUpdateListener {
footer.translationY = it.animatedValue
clipRect.bottom = root.measuredHeight + it.animatedValue
root.clipBounds = clipRect
}1
.start()
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
val clipRect = Rect()
clipRect.right = root.measuredWidth
clipRect.bottom = root.measuredHeight - sizeChange
root.clipBounds = clipRect
ObjectAnimator
.ofFloat(-sizeChange, 0f)
.addUpdateListener {
footer.translationY = it.animatedValue
clipRect.bottom = root.measuredHeight + it.animatedValue
root.clipBounds = clipRect
}1
.start()
}2
Expand
val oldHeight = textView.measuredHeight
showFullText() // <-- request layout
textView.viewTreeObserver.addOnPreDrawListener {
val sizeChange = textView.measuredHeight - oldHeight
footer.translationY -= sizeChange
val clipRect = Rect()
clipRect.right = root.measuredWidth
clipRect.bottom = root.measuredHeight - sizeChange
root.clipBounds = clipRect
ObjectAnimator
.ofFloat(-sizeChange, 0f)
.addUpdateListener {
footer.translationY = it.animatedValue
clipRect.bottom = root.measuredHeight + it.animatedValue
root.clipBounds = clipRect
}1
.start()
}2
Expand
val sizeChange = textView.measuredHeight - collapsedHeight
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
ObjectAnimator.ofInt(0, sizeChange).apply {
}3
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
ObjectAnimator.ofInt(0, sizeChange).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
}3
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
ObjectAnimator.ofInt(0, sizeChange).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
clipRect.bottom = root.measuredHeight - animatedValue
footer.translationY -= animatedValue
}1
}3
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
ObjectAnimator.ofInt(0, sizeChange).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
clipRect.bottom = root.measuredHeight - animatedValue
footer.translationY -= animatedValue
}1
}3
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
ObjectAnimator.ofInt(0, sizeChange).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
clipRect.bottom = root.measuredHeight - animatedValue
footer.translationY -= animatedValue
}1
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
showShortText() // <-- request layout
}2
})
}3
Collapse
val sizeChange = textView.measuredHeight - collapsedHeight
val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight)
ObjectAnimator.ofInt(0, sizeChange).apply {
duration = 1000
interpolator = FastOutSlowInInterpolator()
addUpdateListener {
clipRect.bottom = root.measuredHeight - animatedValue
footer.translationY -= animatedValue
}1
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
showShortText() // <-- request layout
}2
})
}3
Collapse
Things to watch out for
Things to watch out for
• background drawables
Things to watch out for
• background drawables
• animate drawable bounds
Things to watch out for
• background drawables
• animate drawable bounds
• animating complex content
Things to watch out for
• background drawables
• animate drawable bounds
• animating complex content
• animating within scrollable container
Things to watch out for
• background drawables
• animate drawable bounds
• animating complex content
• animating within scrollable container
Things to watch out for
• background drawables
• animate drawable bounds
• animating complex content
• animating within scrollable container
Things to watch out for
Animating LayoutParams is
*not* bad
Animating LayoutParams is *not* bad
• know exactly which parts of layout are affected by your animation
Animating LayoutParams is *not* bad
• know exactly which parts of layout are affected by your animation
• measure performance with "Debug GPU Overdraw"
Animating LayoutParams is *not* bad
• know exactly which parts of layout are affected by your animation
• measure performance with "Debug GPU Overdraw"
• there is more than 1 way to achieve what you need
Animating LayoutParams is *not* bad
Thank you!
Pasha Dudka
@paveldudka
www.trickyandroid.com

More Related Content

What's hot

Design functional solutions in Java, a practical example
Design functional solutions in Java, a practical exampleDesign functional solutions in Java, a practical example
Design functional solutions in Java, a practical exampleMarian Wamsiedel
 
Data Persistence in Android with Room Library
Data Persistence in Android with Room LibraryData Persistence in Android with Room Library
Data Persistence in Android with Room LibraryReinvently
 
Java IO Streams V4
Java IO Streams V4Java IO Streams V4
Java IO Streams V4Sunil OS
 
Exception handling in asp.net
Exception handling in asp.netException handling in asp.net
Exception handling in asp.netNeelesh Shukla
 
Inline Functions and Default arguments
Inline Functions and Default argumentsInline Functions and Default arguments
Inline Functions and Default argumentsNikhil Pandit
 
Dependency injection in Java, from naive to functional
Dependency injection in Java, from naive to functionalDependency injection in Java, from naive to functional
Dependency injection in Java, from naive to functionalMarian Wamsiedel
 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC FrameworkBala Kumar
 
Autoboxing and unboxing
Autoboxing and unboxingAutoboxing and unboxing
Autoboxing and unboxingGeetha Manohar
 
Fiche1 ex-sous-programme
Fiche1 ex-sous-programmeFiche1 ex-sous-programme
Fiche1 ex-sous-programmeBaghdadi Wajih
 
Algorithmique programmation2018
Algorithmique programmation2018Algorithmique programmation2018
Algorithmique programmation2018salah fenni
 
Résumer sur les fichier et les enregistrement
Résumer sur les fichier et les enregistrementRésumer sur les fichier et les enregistrement
Résumer sur les fichier et les enregistrementborhen boukthir
 
Two dimensional array
Two dimensional arrayTwo dimensional array
Two dimensional arrayRajendran
 
Chapter 1 : Balagurusamy_ Programming ANsI in C
Chapter 1  :  Balagurusamy_ Programming ANsI in C Chapter 1  :  Balagurusamy_ Programming ANsI in C
Chapter 1 : Balagurusamy_ Programming ANsI in C BUBT
 
Iterarators and generators in python
Iterarators and generators in pythonIterarators and generators in python
Iterarators and generators in pythonSarfaraz Ghanta
 

What's hot (20)

Design functional solutions in Java, a practical example
Design functional solutions in Java, a practical exampleDesign functional solutions in Java, a practical example
Design functional solutions in Java, a practical example
 
Résumé javascript
Résumé javascriptRésumé javascript
Résumé javascript
 
Data Persistence in Android with Room Library
Data Persistence in Android with Room LibraryData Persistence in Android with Room Library
Data Persistence in Android with Room Library
 
Constants in java
Constants in javaConstants in java
Constants in java
 
Support JEE Servlet Jsp MVC M.Youssfi
Support JEE Servlet Jsp MVC M.YoussfiSupport JEE Servlet Jsp MVC M.Youssfi
Support JEE Servlet Jsp MVC M.Youssfi
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
Java IO Streams V4
Java IO Streams V4Java IO Streams V4
Java IO Streams V4
 
Exception handling in asp.net
Exception handling in asp.netException handling in asp.net
Exception handling in asp.net
 
Inline Functions and Default arguments
Inline Functions and Default argumentsInline Functions and Default arguments
Inline Functions and Default arguments
 
Dependency injection in Java, from naive to functional
Dependency injection in Java, from naive to functionalDependency injection in Java, from naive to functional
Dependency injection in Java, from naive to functional
 
Autoboxing And Unboxing In Java
Autoboxing And Unboxing In JavaAutoboxing And Unboxing In Java
Autoboxing And Unboxing In Java
 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC Framework
 
Autoboxing and unboxing
Autoboxing and unboxingAutoboxing and unboxing
Autoboxing and unboxing
 
Fiche1 ex-sous-programme
Fiche1 ex-sous-programmeFiche1 ex-sous-programme
Fiche1 ex-sous-programme
 
Algorithmique programmation2018
Algorithmique programmation2018Algorithmique programmation2018
Algorithmique programmation2018
 
Résumer sur les fichier et les enregistrement
Résumer sur les fichier et les enregistrementRésumer sur les fichier et les enregistrement
Résumer sur les fichier et les enregistrement
 
Two dimensional array
Two dimensional arrayTwo dimensional array
Two dimensional array
 
NumPy.pptx
NumPy.pptxNumPy.pptx
NumPy.pptx
 
Chapter 1 : Balagurusamy_ Programming ANsI in C
Chapter 1  :  Balagurusamy_ Programming ANsI in C Chapter 1  :  Balagurusamy_ Programming ANsI in C
Chapter 1 : Balagurusamy_ Programming ANsI in C
 
Iterarators and generators in python
Iterarators and generators in pythonIterarators and generators in python
Iterarators and generators in python
 

Similar to Expand/Collapse animation on Android

Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesAndrás Papp
 
WPF L02-Graphics, Binding and Animation
WPF L02-Graphics, Binding and AnimationWPF L02-Graphics, Binding and Animation
WPF L02-Graphics, Binding and AnimationMohammad Shaker
 
Create a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfCreate a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfarihantmobileselepun
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutinesFabio Collini
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기진성 오
 
Fabric.js @ Falsy Values
Fabric.js @ Falsy ValuesFabric.js @ Falsy Values
Fabric.js @ Falsy ValuesJuriy Zaytsev
 
Creating custom views
Creating custom viewsCreating custom views
Creating custom viewsMu Chun Wang
 
Макс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложенияхМакс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложенияхCocoaHeads
 
The Ring programming language version 1.3 book - Part 46 of 88
The Ring programming language version 1.3 book - Part 46 of 88The Ring programming language version 1.3 book - Part 46 of 88
The Ring programming language version 1.3 book - Part 46 of 88Mahmoud Samir Fayed
 
The Ring programming language version 1.5.3 book - Part 70 of 184
The Ring programming language version 1.5.3 book - Part 70 of 184The Ring programming language version 1.5.3 book - Part 70 of 184
The Ring programming language version 1.5.3 book - Part 70 of 184Mahmoud Samir Fayed
 
Kotlin Mullets
Kotlin MulletsKotlin Mullets
Kotlin MulletsJames Ward
 
Scientific Computing with Python Webinar: Traits
Scientific Computing with Python Webinar: TraitsScientific Computing with Python Webinar: Traits
Scientific Computing with Python Webinar: TraitsEnthought, Inc.
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }John De Goes
 
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevelFun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevelDroidConTLV
 
Animations avec Compose : rendez vos apps chat-oyantes
Animations avec Compose : rendez vos apps chat-oyantesAnimations avec Compose : rendez vos apps chat-oyantes
Animations avec Compose : rendez vos apps chat-oyantesAntoine Robiez
 
The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196Mahmoud Samir Fayed
 
Александр Зимин – Анимация как средство самовыражения
Александр Зимин – Анимация как средство самовыраженияАлександр Зимин – Анимация как средство самовыражения
Александр Зимин – Анимация как средство самовыраженияCocoaHeads
 

Similar to Expand/Collapse animation on Android (20)

Corona sdk
Corona sdkCorona sdk
Corona sdk
 
Functional programming techniques in real-world microservices
Functional programming techniques in real-world microservicesFunctional programming techniques in real-world microservices
Functional programming techniques in real-world microservices
 
WPF L02-Graphics, Binding and Animation
WPF L02-Graphics, Binding and AnimationWPF L02-Graphics, Binding and Animation
WPF L02-Graphics, Binding and Animation
 
Miracle of std lib
Miracle of std libMiracle of std lib
Miracle of std lib
 
Create a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdfCreate a java project that - Draw a circle with three random init.pdf
Create a java project that - Draw a circle with three random init.pdf
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
SVGo workshop
SVGo workshopSVGo workshop
SVGo workshop
 
Fabric.js @ Falsy Values
Fabric.js @ Falsy ValuesFabric.js @ Falsy Values
Fabric.js @ Falsy Values
 
Creating custom views
Creating custom viewsCreating custom views
Creating custom views
 
Макс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложенияхМакс Грибов — Использование SpriteKit в неигровых приложениях
Макс Грибов — Использование SpriteKit в неигровых приложениях
 
The Ring programming language version 1.3 book - Part 46 of 88
The Ring programming language version 1.3 book - Part 46 of 88The Ring programming language version 1.3 book - Part 46 of 88
The Ring programming language version 1.3 book - Part 46 of 88
 
The Ring programming language version 1.5.3 book - Part 70 of 184
The Ring programming language version 1.5.3 book - Part 70 of 184The Ring programming language version 1.5.3 book - Part 70 of 184
The Ring programming language version 1.5.3 book - Part 70 of 184
 
Kotlin Mullets
Kotlin MulletsKotlin Mullets
Kotlin Mullets
 
Scientific Computing with Python Webinar: Traits
Scientific Computing with Python Webinar: TraitsScientific Computing with Python Webinar: Traits
Scientific Computing with Python Webinar: Traits
 
Atomically { Delete Your Actors }
Atomically { Delete Your Actors }Atomically { Delete Your Actors }
Atomically { Delete Your Actors }
 
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevelFun with flutter animations - Divyanshu Bhargava, GoHighLevel
Fun with flutter animations - Divyanshu Bhargava, GoHighLevel
 
Animations avec Compose : rendez vos apps chat-oyantes
Animations avec Compose : rendez vos apps chat-oyantesAnimations avec Compose : rendez vos apps chat-oyantes
Animations avec Compose : rendez vos apps chat-oyantes
 
The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196
 
Александр Зимин – Анимация как средство самовыражения
Александр Зимин – Анимация как средство самовыраженияАлександр Зимин – Анимация как средство самовыражения
Александр Зимин – Анимация как средство самовыражения
 

Recently uploaded

PHYSICS PROJECT BY MSC - NANOTECHNOLOGY
PHYSICS PROJECT BY MSC  - NANOTECHNOLOGYPHYSICS PROJECT BY MSC  - NANOTECHNOLOGY
PHYSICS PROJECT BY MSC - NANOTECHNOLOGYpruthirajnayak525
 
call girls in delhi malviya nagar @9811711561@
call girls in delhi malviya nagar @9811711561@call girls in delhi malviya nagar @9811711561@
call girls in delhi malviya nagar @9811711561@vikas rana
 
Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...
Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...
Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...Salam Al-Karadaghi
 
OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...
OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...
OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...NETWAYS
 
OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...
OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...
OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...NETWAYS
 
Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...
Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...
Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...NETWAYS
 
Anne Frank A Beacon of Hope amidst darkness ppt.pptx
Anne Frank A Beacon of Hope amidst darkness ppt.pptxAnne Frank A Beacon of Hope amidst darkness ppt.pptx
Anne Frank A Beacon of Hope amidst darkness ppt.pptxnoorehahmad
 
NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)
NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)
NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)Basil Achie
 
Open Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdf
Open Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdfOpen Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdf
Open Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdfhenrik385807
 
Philippine History cavite Mutiny Report.ppt
Philippine History cavite Mutiny Report.pptPhilippine History cavite Mutiny Report.ppt
Philippine History cavite Mutiny Report.pptssuser319dad
 
Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Genesis part 2 Isaiah Scudder 04-24-2024.pptx
Genesis part 2 Isaiah Scudder 04-24-2024.pptxGenesis part 2 Isaiah Scudder 04-24-2024.pptx
Genesis part 2 Isaiah Scudder 04-24-2024.pptxFamilyWorshipCenterD
 
Simulation-based Testing of Unmanned Aerial Vehicles with Aerialist
Simulation-based Testing of Unmanned Aerial Vehicles with AerialistSimulation-based Testing of Unmanned Aerial Vehicles with Aerialist
Simulation-based Testing of Unmanned Aerial Vehicles with AerialistSebastiano Panichella
 
miladyskindiseases-200705210221 2.!!pptx
miladyskindiseases-200705210221 2.!!pptxmiladyskindiseases-200705210221 2.!!pptx
miladyskindiseases-200705210221 2.!!pptxCarrieButtitta
 
Dutch Power - 26 maart 2024 - Henk Kras - Circular Plastics
Dutch Power - 26 maart 2024 - Henk Kras - Circular PlasticsDutch Power - 26 maart 2024 - Henk Kras - Circular Plastics
Dutch Power - 26 maart 2024 - Henk Kras - Circular PlasticsDutch Power
 
OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...
OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...
OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...NETWAYS
 
SBFT Tool Competition 2024 -- Python Test Case Generation Track
SBFT Tool Competition 2024 -- Python Test Case Generation TrackSBFT Tool Competition 2024 -- Python Test Case Generation Track
SBFT Tool Competition 2024 -- Python Test Case Generation TrackSebastiano Panichella
 
Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...
Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...
Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...NETWAYS
 
Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...
Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...
Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...marjmae69
 
The Ten Facts About People With Autism Presentation
The Ten Facts About People With Autism PresentationThe Ten Facts About People With Autism Presentation
The Ten Facts About People With Autism PresentationNathan Young
 

Recently uploaded (20)

PHYSICS PROJECT BY MSC - NANOTECHNOLOGY
PHYSICS PROJECT BY MSC  - NANOTECHNOLOGYPHYSICS PROJECT BY MSC  - NANOTECHNOLOGY
PHYSICS PROJECT BY MSC - NANOTECHNOLOGY
 
call girls in delhi malviya nagar @9811711561@
call girls in delhi malviya nagar @9811711561@call girls in delhi malviya nagar @9811711561@
call girls in delhi malviya nagar @9811711561@
 
Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...
Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...
Exploring protein-protein interactions by Weak Affinity Chromatography (WAC) ...
 
OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...
OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...
OSCamp Kubernetes 2024 | A Tester's Guide to CI_CD as an Automated Quality Co...
 
OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...
OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...
OSCamp Kubernetes 2024 | SRE Challenges in Monolith to Microservices Shift at...
 
Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...
Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...
Open Source Camp Kubernetes 2024 | Running WebAssembly on Kubernetes by Alex ...
 
Anne Frank A Beacon of Hope amidst darkness ppt.pptx
Anne Frank A Beacon of Hope amidst darkness ppt.pptxAnne Frank A Beacon of Hope amidst darkness ppt.pptx
Anne Frank A Beacon of Hope amidst darkness ppt.pptx
 
NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)
NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)
NATIONAL ANTHEMS OF AFRICA (National Anthems of Africa)
 
Open Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdf
Open Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdfOpen Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdf
Open Source Strategy in Logistics 2015_Henrik Hankedvz-d-nl-log-conference.pdf
 
Philippine History cavite Mutiny Report.ppt
Philippine History cavite Mutiny Report.pptPhilippine History cavite Mutiny Report.ppt
Philippine History cavite Mutiny Report.ppt
 
Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Rohini Delhi 💯Call Us 🔝8264348440🔝
 
Genesis part 2 Isaiah Scudder 04-24-2024.pptx
Genesis part 2 Isaiah Scudder 04-24-2024.pptxGenesis part 2 Isaiah Scudder 04-24-2024.pptx
Genesis part 2 Isaiah Scudder 04-24-2024.pptx
 
Simulation-based Testing of Unmanned Aerial Vehicles with Aerialist
Simulation-based Testing of Unmanned Aerial Vehicles with AerialistSimulation-based Testing of Unmanned Aerial Vehicles with Aerialist
Simulation-based Testing of Unmanned Aerial Vehicles with Aerialist
 
miladyskindiseases-200705210221 2.!!pptx
miladyskindiseases-200705210221 2.!!pptxmiladyskindiseases-200705210221 2.!!pptx
miladyskindiseases-200705210221 2.!!pptx
 
Dutch Power - 26 maart 2024 - Henk Kras - Circular Plastics
Dutch Power - 26 maart 2024 - Henk Kras - Circular PlasticsDutch Power - 26 maart 2024 - Henk Kras - Circular Plastics
Dutch Power - 26 maart 2024 - Henk Kras - Circular Plastics
 
OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...
OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...
OSCamp Kubernetes 2024 | Zero-Touch OS-Infrastruktur für Container und Kubern...
 
SBFT Tool Competition 2024 -- Python Test Case Generation Track
SBFT Tool Competition 2024 -- Python Test Case Generation TrackSBFT Tool Competition 2024 -- Python Test Case Generation Track
SBFT Tool Competition 2024 -- Python Test Case Generation Track
 
Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...
Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...
Open Source Camp Kubernetes 2024 | Monitoring Kubernetes With Icinga by Eric ...
 
Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...
Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...
Gaps, Issues and Challenges in the Implementation of Mother Tongue Based-Mult...
 
The Ten Facts About People With Autism Presentation
The Ten Facts About People With Autism PresentationThe Ten Facts About People With Autism Presentation
The Ten Facts About People With Autism Presentation
 

Expand/Collapse animation on Android

  • 2.
  • 3.
  • 5. val animator = ObjectAnimator.ofInt(0, 100) Animating values
  • 6. val animator = ObjectAnimator.ofInt(0, 100) animator.duration = 1000 Animating values
  • 7. val animator = ObjectAnimator.ofInt(0, 100) animator.duration = 1000 animator.interpolator = FastOutSlowInInterpolator() Animating values
  • 8. val animator = ObjectAnimator.ofInt(0, 100) animator.duration = 1000 animator.interpolator = FastOutSlowInInterpolator() animator.addUpdateListener { Log.d("pasha", "${it.animatedValue}") }1 Animating values
  • 9. val animator = ObjectAnimator.ofInt(0, 100) animator.duration = 1000 animator.interpolator = FastOutSlowInInterpolator() animator.addUpdateListener { Log.d("pasha", "${it.animatedValue}") }1 animator.start() Animating values
  • 10. val animator = ObjectAnimator.ofInt(0, 100) animator.apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { Log.d("pasha", "${it.animatedValue}") }1 start() }2 Animating values
  • 14. val animator = ObjectAnimator.ofFloat(1f, 1.5f) animator.apply { duration = 1000 interpolator = OvershootInterpolator() addUpdateListener { view.scaleX = it.animatedValue view.scaleY = it.animatedValue }1 start() }2 Animating view properties
  • 15. val animator = ObjectAnimator.ofFloat(1f, 1.5f) animator.apply { duration = 1000 interpolator = OvershootInterpolator() addUpdateListener { view.scaleX = it.animatedValue view.scaleY = it.animatedValue }1 start() }2 Animating view properties
  • 16. val animator = ObjectAnimator.ofFloat(1f, 1.5f) animator.apply { duration = 1000 interpolator = OvershootInterpolator() addUpdateListener { view.scaleX = it.animatedValue view.scaleY = it.animatedValue }1 start() }2 Animating view properties
  • 17. val animator = ObjectAnimator.ofFloat(1f, 1.5f) animator.apply { duration = 1000 interpolator = OvershootInterpolator() addUpdateListener { view.scaleX = it.animatedValue view.scaleY = it.animatedValue }1 start() }2 Animating view properties
  • 24. Changing view properties does not trigger measure/layout pass
  • 25.
  • 26.
  • 27.
  • 29. private fun expand(view: View) { }3 Animate LayoutParams!
  • 30. private fun expand(view: View) { val oldHeight = view.measuredHeight val newHeight = oldHeight + 300 }3 Animate LayoutParams!
  • 31. private fun expand(view: View) { val oldHeight = view.measuredHeight val newHeight = oldHeight + 300 ObjectAnimator.ofInt(oldHeight, newHeight).apply { }2 }3 Animate LayoutParams!
  • 32. private fun expand(view: View) { val oldHeight = view.measuredHeight val newHeight = oldHeight + 300 ObjectAnimator.ofInt(oldHeight, newHeight).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() }2 }3 Animate LayoutParams!
  • 33. private fun expand(view: View) { val oldHeight = view.measuredHeight val newHeight = oldHeight + 300 ObjectAnimator.ofInt(oldHeight, newHeight).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { view.layoutParams.height = it.animatedValue }1 start() }2 }3 Animate LayoutParams!
  • 34. private fun expand(view: View) { val oldHeight = view.measuredHeight val newHeight = oldHeight + 300 ObjectAnimator.ofInt(oldHeight, newHeight).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { view.layoutParams.height = it.animatedValue view.requestLayout() }1 start() }2 }3 Animate LayoutParams!
  • 35. private fun expand(view: View) { val oldHeight = view.measuredHeight val newHeight = oldHeight + 300 ObjectAnimator.ofInt(oldHeight, newHeight).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { view.layoutParams.height = it.animatedValue view.requestLayout() }1 start() }2 }3 Animate LayoutParams!
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 43.
  • 45. val oldHeight = textView.measuredHeight Expand
  • 46. val oldHeight = textView.measuredHeight showFullText() // <-- request layout Expand
  • 47. val oldHeight = textView.measuredHeight showFullText() // <-- request layout Expand
  • 48. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { }2 Expand
  • 49. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight }2 Expand
  • 50. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight }2 Expand
  • 51. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange }2 Expand
  • 52. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange }2 Expand
  • 53. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange val clipRect = Rect() clipRect.right = root.measuredWidth clipRect.bottom = root.measuredHeight - sizeChange root.clipBounds = clipRect }2 Expand
  • 54. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange val clipRect = Rect() clipRect.right = root.measuredWidth clipRect.bottom = root.measuredHeight - sizeChange root.clipBounds = clipRect }2 Expand
  • 55. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange val clipRect = Rect() clipRect.right = root.measuredWidth clipRect.bottom = root.measuredHeight - sizeChange root.clipBounds = clipRect ObjectAnimator .ofFloat(-sizeChange, 0f) .addUpdateListener { footer.translationY = it.animatedValue clipRect.bottom = root.measuredHeight + it.animatedValue root.clipBounds = clipRect }1 .start() }2 Expand
  • 56. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange val clipRect = Rect() clipRect.right = root.measuredWidth clipRect.bottom = root.measuredHeight - sizeChange root.clipBounds = clipRect ObjectAnimator .ofFloat(-sizeChange, 0f) .addUpdateListener { footer.translationY = it.animatedValue clipRect.bottom = root.measuredHeight + it.animatedValue root.clipBounds = clipRect }1 .start() }2 Expand
  • 57. val oldHeight = textView.measuredHeight showFullText() // <-- request layout textView.viewTreeObserver.addOnPreDrawListener { val sizeChange = textView.measuredHeight - oldHeight footer.translationY -= sizeChange val clipRect = Rect() clipRect.right = root.measuredWidth clipRect.bottom = root.measuredHeight - sizeChange root.clipBounds = clipRect ObjectAnimator .ofFloat(-sizeChange, 0f) .addUpdateListener { footer.translationY = it.animatedValue clipRect.bottom = root.measuredHeight + it.animatedValue root.clipBounds = clipRect }1 .start() }2 Expand
  • 58.
  • 59.
  • 60. val sizeChange = textView.measuredHeight - collapsedHeight Collapse
  • 61. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) Collapse
  • 62. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) ObjectAnimator.ofInt(0, sizeChange).apply { }3 Collapse
  • 63. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) ObjectAnimator.ofInt(0, sizeChange).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() }3 Collapse
  • 64. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) ObjectAnimator.ofInt(0, sizeChange).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { clipRect.bottom = root.measuredHeight - animatedValue footer.translationY -= animatedValue }1 }3 Collapse
  • 65. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) ObjectAnimator.ofInt(0, sizeChange).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { clipRect.bottom = root.measuredHeight - animatedValue footer.translationY -= animatedValue }1 }3 Collapse
  • 66. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) ObjectAnimator.ofInt(0, sizeChange).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { clipRect.bottom = root.measuredHeight - animatedValue footer.translationY -= animatedValue }1 addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { showShortText() // <-- request layout }2 }) }3 Collapse
  • 67. val sizeChange = textView.measuredHeight - collapsedHeight val clipRect = Rect(0, 0, root.measuredWidth, root.measuredHeight) ObjectAnimator.ofInt(0, sizeChange).apply { duration = 1000 interpolator = FastOutSlowInInterpolator() addUpdateListener { clipRect.bottom = root.measuredHeight - animatedValue footer.translationY -= animatedValue }1 addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { showShortText() // <-- request layout }2 }) }3 Collapse
  • 68.
  • 69.
  • 70. Things to watch out for
  • 71. Things to watch out for
  • 73. • background drawables • animate drawable bounds Things to watch out for
  • 74. • background drawables • animate drawable bounds • animating complex content Things to watch out for
  • 75. • background drawables • animate drawable bounds • animating complex content • animating within scrollable container Things to watch out for
  • 76. • background drawables • animate drawable bounds • animating complex content • animating within scrollable container Things to watch out for
  • 77. • background drawables • animate drawable bounds • animating complex content • animating within scrollable container Things to watch out for
  • 80. • know exactly which parts of layout are affected by your animation Animating LayoutParams is *not* bad
  • 81. • know exactly which parts of layout are affected by your animation • measure performance with "Debug GPU Overdraw" Animating LayoutParams is *not* bad
  • 82. • know exactly which parts of layout are affected by your animation • measure performance with "Debug GPU Overdraw" • there is more than 1 way to achieve what you need Animating LayoutParams is *not* bad