I have a simple fade out animation function for my android app, it works, but the issue I am having is that, after the fade out animation has run, the view (TextView in this case) does not stay faded out, the alpha value becomes 1 again.
Here is the fadeOut function code:
fun fadeOut(duration: Long = 100) : AlphaAnimation{
val fadeOut = AlphaAnimation(1f, 0f)
fadeOut.interpolator = DecelerateInterpolator()
fadeOut.duration = duration
return fadeOut
}
And I use it like this:
myTextView.startAnimation(fadeOut(500))
Any help or advice will be highly appreciated.
I think Animation::setFillAfter function would do the trick for you, the code would be like this:
val animation = fadeOut(500)
animation.fillAfter = true
myTextView.startAnimation(animation)
Although, this solution only preserves the alpha value of the view after the animation ends, if you want to change the visibility of the view, you need to change it when the animation ends using Animation.AnimationListener interface, the code would be like this:
myTextView.startAnimation(fadeOut(500).apply {
setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
myTextView.visibility = View.GONE
}
override fun onAnimationRepeat(animation: Animation?) {
}
})
})
You can set visibility in handler after running animation
myTextView.startAnimation(fadeOut(500))
Handler().postDelayed({
myTextView.visibility = View.GONE
},500)
Related
What I am trying to do is retrieve data from the server when I click a button. When I click the button, I want to show my "Loading..." TextView for 2 seconds, and only then show the data I got from the server. How can I do this?
For now my animation is working, but the data is showing almost instantly. I want to delay that. Using Thread.sleep(2000) causes both the data and Loading to be delayed.
val loadingAnimation :TextView = findViewById<TextView>(R.id.loadingAnimationTextView)
val alphaAnim = AlphaAnimation(1.0f, 0.0f)
alphaAnim.startOffset = 0
alphaAnim.duration = 2000
alphaAnim.setAnimationListener(object : AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {
//not sure what code to put here
}
override fun onAnimationEnd(animation: Animation) {
// make invisible when animation completes, you could also remove the view from the layout
loadingAnimation.setVisibility(View.INVISIBLE)
}
override fun onAnimationStart(animation: Animation?) {
loadingAnimation.setVisibility(View.VISIBLE)
}
})
loadingAnimation.setAnimation(alphaAnim)
Thread.sleep(2000)
You can use the handler for this task.
Handler(Looper.getMainLooper()).postDelayed({
// Show you data here
loadingAnimation.setVisibility(View.INVISIBLE)
}, 2000)
Here, 2000 = 2 seconds
It's probably easier to use the ViewPropertyAnimator stuff:
loadingAnimation.animate()
.alpha(0)
.duration(2000)
.withEndAction {
// data displaying code goes here
}.start()
but honestly I don't think there's anything wrong with populating an invisible list, and just making it visible when you want to display it. But that up there is a way to chain runnable code and animations, one after the other
I build Android apps using the MVP pattern and I'm often breaking up my UI into various sections like this:
<ConstraintLayout
android:id="#+id/recyclerSection"
<ConstraintLayout
android:id="#+id/errorSection"
<ConstraintLayout
android:id="#+id/emptySection"
Then in my presenter I'll call
view.showError()
and my view ends up with functions that look like this:
override fun showError(){
recyclerSection.visibility = View.GONE
errorSection.visibility = View.VISIBLE
emptySection.visibility = View.GONE
}
override fun showList(){
recyclerSection.visibility = View.VISIBLE
errorSection.visibility = View.GONE
emptySection.visibility = View.GONE
}
Is there a more elegant way to code this to achieve this toggling of view sections?
What do you mean with elegant? Here's an fade extension which is pretty nice
fun View.fadeToVisible(time: Long) {
alpha = 0f
animate()
.alpha(1f)
.setDuration(time)
.withStartAction {
visibility = View.VISIBLE
}
.start()
}
fun View.fadeToGone(time: Long) {
alpha = 1f
animate()
.alpha(0f)
.setDuration(time)
.withEndAction {
visibility = View.GONE
}
.start()
}
And then you use it like this (with 200 ms time):
override fun showError(){
recyclerSection.fadeToGone(200)
errorSection.fadeToVisible(200)
emptySection.fadeToGone(200)
}
override fun showList(){
recyclerSection.fadeToVisible(200)
errorSection.fadeToGone(200)
emptySection.fadeToGone(200)
}
However it's a matter of taste :)
I have some animations in my Android app and I'd like to change my code in order to take advantage of Android KTX. Sadly, I don't really understand the documentation about it. Could someone tell me how I can improve this code with the help of Android KTX?
view
.animate()
.translationY(view.height.toFloat())
.setDuration(3000)
.setInterpolator(AccelerateInterpolator())
.setListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) {}
override fun onAnimationRepeat(animation: Animator?) {}
override fun onAnimationCancel(animation: Animator?) {}
override fun onAnimationEnd(animation: Animator?) {
// Do whatever I want
}
})
Of course, I have already added the dependency in my Gradle file:
implementation 'androidx.core:core-ktx:1.0.2'
Thank you very much in advance :)
Android KTX has doOnEnd { /** Do whatever you want **/ } and other extension functions for android.animation.Animator. When you call view.animate(), it returns ViewPropertyAnimator which is not inherited from android.animation.Animator class. Therefore you cannot view.animate().doOnEnd { /** Do whatever you want **/ } provided by Android KTX.
However, you can use withEndAction to do anything when animation ends. withEndAction is part of default ViewPropertyAnimator, so, you do not need to have Android KTX to use that:
view
.animate()
.translationY(image.height.toFloat())
.setDuration(3000)
.setInterpolator(AccelerateInterpolator())
.withEndAction {
// Do whatever you want
}
Android KTX provides some animation event listener functions for Animator instances. As view.animate() returns an instance of ViewPropertyAnimator, you should use a subclass of Animator (like ObjectAnimator) to be able to use KTX capabilities. for example:
ObjectAnimator.ofFloat(view, "translationY", view.height.toFloat()).apply {
duration = 3000
interpolator = AccelerateInterpolator()
// Using KTX extension function:
doOnEnd { /** Do whatever you want **/ }
start()
}
I'm trying to set visibility of a view to GONE after set its alpha to zero :
view.animate()
.alpha(0.0f)
.setDuration(500)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
view.visibility= GONE
}
})
But animation shows twice. In the other words, my view shows and hides again after calling view.visibility= GONE.
Any ideas?
My mistake was adding android:animateLayoutChanges="true" in the root of layout. It animates my view again!
When you are using this view animation there is a method which is withEndAction which takes a runnable and with lambda it looks something like this :
view.animate()
.alpha(0.0f)
.setDuration(500).withEndAction{
view.alpha = 0.0f
view.visibility= GONE
}
Try this.
Hope this helps.
I am trying to move Imageview in curved path to a particular point. So I make use of this library. I have to move the imageview in the curved path and the image view should return to its original position. This is one cycle. But it should repeat indefinitely until I press a button in that activity.
It works as expected but when the imageview finishes one cycle and about to start the next cycle, the image view is shaken little bit at the starting point (This is not happening for the first time but it happens for second and so forth) and then the animation proceeds normally.
private fun startAnimation(thermView: ImageView, thermAnimIdentifierView: TextView) {
Log.d(TAG, "****************************************************Start Animation")
val arcAnimator = ArcAnimator.createArcAnimator(thermView, thermAnimIdentifierView, 360f, Side.RIGHT)
arcAnimator.setDuration(5000)
arcAnimator.setInterpolator(CycleInterpolator(0.5f))
arcAnimator.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
val arcAnimator = ArcAnimator.createArcAnimator(thermView, thermAnimIdentifierView, 360f, Side.RIGHT)
arcAnimator.setStartDelay(500)
arcAnimator.setDuration(5000)
arcAnimator.setInterpolator(CycleInterpolator(0.5f))
arcAnimator.addListener(this)
arcAnimator.start()
}
override fun onAnimationCancel(animation: Animator) {
}
override fun onAnimationRepeat(animation: Animator) {
}
})
arcAnimator.start()
}