Multiple views and animations lagging - android

I have two RelativeLayout views. The first one has about three children. The second one has only the first one view as its child. I have two animations, fadeIn and translateIn, which must be applied to the views firstView and secondView respectively. The code below is working. They start and end at the same time, but it's lagging. It's not so smooth. Is there any thing I can do to run them simultaneously and smooth?
Here's the code:
private static final int duration = 500;
protected static boolean ANIMATION_FINISHED;
protected static void onShowAnimation() {
int width;
ANIMATION_FINISHED = false;
width = getScreenWidth();
final AlphaAnimation fadeIn = new AlphaAnimation(0, 1);
final TranslateAnimation translateIn = new TranslateAnimation(-width, 0, 1, 1);
fadeIn.setDuration(duration);
translateIn.setDuration(duration);
firstView.startAnimation(translateIn);
secondView.startAnimation(fadeIn);
secondView.postDelayed(new Runnable() {
#Override
public void run() {
ANIMATION_FINISHED = true;
}
}, duration);
}

animations up to gingerbread always been pretty laggy in Android. In Honeycomb and forward they fixed it with the new framework, but then the developers (that's you) must know which framework to use.
to have a nice smooth hardware accelerated animation you should use the android.animation not the android.view.animation
Here you have the complete guide for the property animation framework: https://developer.android.com/guide/topics/graphics/prop-animation.html
and here is the base class for it:
https://developer.android.com/reference/android/animation/package-summary.html
if you need to target devices on gingerbread or below, I suggest you to use the NineOldAndroid library that automatically handles the best possible framework for the device. (Remembering it will still be laggy on 2.3, but at least 3.0+ will be smooth).
ps.: You shouldn't use a postDelayed to know when the animation is over, instead use an Animation Listener

After searching a lot finally i successfully remove lagging during animation.
you need to set,
yourAnimatedView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
before starting animation, and after completion of animation you need to set,
yourAnimatedView.setLayerType(View.LAYER_TYPE_NONE, null);
During animations your views may be redrawn each frame. If you use view layers, instead of having to redraw each frame, views render once into an off-screen buffer which can be reused.
In addition, hardware layers are cached on the GPU, which makes certain operations during animation much faster. Simple transformations (translation, rotation, scaling and alpha) can be rendered quickly with layers. Since many animations are just a combination of these transformations, layers can supercharge animation performance

Related

Android doesn't animate alpha if it's initially zero

I am trying to animate alpha of an Android view (two animations, both fade in and fade out). It all works fine if the view's alpha is initially 1, by default. However, I want that view to be transparent initially, hence I've set it's alpha to zero:
indicatorContainer.setAlpha(0);
Now, the animations won't work. It will never become visible. If I comment out that line, the view is initially displayed (which I don't want), but my animations works fine when I invoke them. I though it's something trivial but apparently it's not. What am I doing wrong?
UPDATE: I've also tried a floating point 0f instead of integer 0 after reading some API changes involving the setAlpha method, thinking that my call may be calling the incorrect overload, but nothing changed.
Try something like this:
mRelativeLayout.setAlpha(0f);
mRelativeLayout.animate().alpha(1f).setDuration(500).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mRelativeLayout.setVisibility(View.VISIBLE);
//OR
mRelativeLayout.setAlpha(1f);
}
});
I faced same issue where indicatorContainer is ImageButton.
Below code fixes this very, very annoying issue...
// XXX: Does not work if just 0. It calls `ImageView#setAlpha(int)` deprecated method.
indicatorContainer.setAlpha(0.0f);
ViewCompat.animate(indicatorContainer).alpha(1);
One can try following, a more simple way:
view.animate().alpha(1).setDuration(ANIMATION_DURATION);
This might be irrelevant to the OP but I thought I'd share it regardless as it might help someone out in the future.
Please be aware that if you're initial animation combines animate().alpha(0.0f) with a manipulation of the View's Y or X-axis translation (e.g. animate().translationYBy(500) you have to reset this property before fading back in (using animate().alpha(1.0f).
I came across this SO post thinking that setting alpha back to 1.0f was failing when in actual fact it was still working as it should, but the animation was occurring off screen because I hadn't reset my Y-Axis translation (Homer Simpson *doh* moment).
Handily, to easily resolve this issue, you can add a AnimatorEndListener to your animation for when it finishes (as #Nikhil Verma mentioned above) where you can add a single line of code to reset the X/Y-axis translation.
In the scenario I faced I wanted the animation to float down and fade out so adjusted the Y-axis & alpha accordingly. After it had floated and faded I set a Listener to reset the Y axis translation like so:
loadingMask.animate().translationYBy(500); //starts animation by moving it down the screen
loadingMask.animate().alpha(0.0f) //fades out
.setDuration(1500) //over 1.5s
.setListener(new AnimatorEndListener() { //when animation completes
#Override
public void onAnimationEnd(Animator animation) {
loadingMask.setTranslationY(0); //reset the y axis translation
}
});
Now, when I want the animation to repeat again, I can set the alpha of my View to 1.0f and it works as intended.
Here's how I was able to kinda solve for this - not particularly elegant, but manageable:
Set the view to the initial alpha you want 0.0f or otherwise.
When the event occurs where you need the view to have more (or less) visibility/alpha - eg, right before you start an animation - at that point you can update the alpha and then run the animation on the view
I'm still getting some choppiness when the animation repeats, but this approach might work for scenarios where the animation is not repeated

SurfaceView not animating

i have created a surfaceView and attached an alpha fade in and fade out animation but it doesnt seem to animate.
Here is my animation code:
fadeOut = new AlphaAnimation(1.0f, 0.0f);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setDuration(1000);
fadeIn = new AlphaAnimation(0.0f, 1.0f);
fadeIn.setInterpolator(new AccelerateDecelerateInterpolator());
fadeIn.setDuration(1000);
animation = new AnimationSet(false);
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
//this.setAnimation(animation);
animation.setRepeatCount(Animation.INFINITE);
animation.setRepeatMode(Animation.REVERSE);
inside my onDraw method i simply call this
super.onDraw(canvas);
this.startAnimation(animation);
Any suggestions?
Thanks
A SurfaceView is a special kind of view. I'm not so familiar with the exact implementation of it, but what I understood is that it creates more or less a hole in your app, and renders the view outside of the normal framework. This causes that it's not possible to do things like animations on it (or at least limits it).
If you really want a fade in animation, I suggest you implement it yourself in your SurfaceView, or you consider extending from View instead of SurfaceView.
Android ICS (v4) added TextureView which supports animations
Because a SurfaceView’s content does not live in the application’s window, it cannot be transformed (moved, scaled, rotated) efficiently. This makes it difficult to use a SurfaceView inside a ListView or a ScrollView. SurfaceView also cannot interact properly with some features of the UI toolkit such as fading edges or View.setAlpha().
To solve these problems, Android 4.0 introduces a new widget called TextureView that relies on the hardware accelerated 2D rendering pipeline and SurfaceTexture. TextureView offers the same capabilities as SurfaceView but, unlike SurfaceView, behaves as a regular view. You can for instance use a TextureView to display an OpenGL scene or a video stream. The TextureView itself can be animated, scrolled, etc.

How does one implement a horizontally scrolling countdown timer?

Goal
I'd like to implement a countdown timer that just scrolls numbers (not graphics) from left to right.
Effect
The effect would look like the number zooms in from the left, slows down towards the middle, and then zooms off to the right.
Notes
Since I'm already using a TimerTask to execute code every second, I could use that to trigger the next number to scroll across the horizontally-scrolling textview.
Could this just be implemented as a textview inside a scrollview ? Looking for a code sample to start off with....
Using Animations would be the simplest solution. You can create your own or try and combine multiple TranslateAnimations and ScaleAnimations.
This would mean putting each number into its own TextView instead of using a scroll view.
Then you could control the acceleration to the middle with an Interpolator. Interpolators are how Android handles easing. You would probably want the AccelerateDecelerateInterpolator for the speeding up / slowing down effect.
You can use an AnimationSet to apply multiple animations to the same View. Figuring out how to put together a good AnimationSet will be the most challenging part of the project. Make sure to pay attention to the "fill" property. In fact after playing around a little, I think a custom animation is simpler than using the ready made ones.
You can fork my GitHub project that implements a very simple version of this. April 17 and before I used multiple pre made Animations. If you look at the most recent version, you'll see the custom animation.
The timing for each Animation takes care of itself after you set the duration for one Animation. A Handler calls the next number after the previous one finishes. I think this is a little neater than having to call a function every X seconds to update everything.
The outline of functionality:
An Activity (CountDownActivity.java) over sees everything.
The Activitiy's layout XML has a button that is used to start the count down.
Once the countdown starts, the button disappears. It reappears when the count down is done.
The Activity contains a Handler (MotionHandler.java). The Handler controls the movement and timing of the numbers.
The Handler uses a AnimationSet to move the numbers
The AnimationSet is a passed in dependency
This is for flexibility. Simply pass in a different AnimationSet to change how the numbers move
The AnimationSet is made of four Animations a custom Animation (see below)
The AnimationSet uses a shared AccelerateDecelerateInterpolator, which seems to work decently. There are other options, including writing your own.
The Handler uses a delayed message to start the next number
The Handler notifies the Activity when the count down is done using a custom listener (MotionHandler >> CountdownListener)
Rotating the device will restart the count down.
Note - previously I was using four ready made Animations in one AnimationSet, I've edited to include just one custom Animation... You can tweak its algorithm to your liking.
This custom animation uses a Cycloid to make the numbers appear larger and smaller.
/**
* A custom animation to move and scale the numbers.
*
*/
public class NumberAnimation extends Animation
{
final public static float MINIMUM = 3;
private int mHorizontal;
private int mScaling;
public NumberAnimation(int horizontalMovement, int scaling)
{
mHorizontal = horizontalMovement;
mScaling = scaling;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
// Cycloid repeats every 2pi - scale interpolatedTime to that
double time = 2 * Math.PI * interpolatedTime;
// Cycloid function
float currentScale = (float) (mScaling * (1 - Math.cos(time))) + MINIMUM;
Matrix matrix = t.getMatrix();
matrix.preScale(currentScale, currentScale);
matrix.postTranslate(mHorizontal * interpolatedTime, 0);
}
}
Easing will help you control the speed.

Android Animate view from off screen not working

I have a view that is positioned totally off screen and I am trying to animate it onto the screen.
When I call:
view.startAnimation(tA);
nothing happens, tA.initialize and tA.applyTransformation never get called.
If I move the view so that any part of it is visible before I start the animation, then the animation works correctly.
What is preventing a view from being animated when it is positioned off the parent View?
It's my understanding from researching the same problem that Android Animations do not do well when provided with offscreen coordinates for their start or finish.
There is some dialog on the Android forums about this bug having been addressed but I'm still experiencing problems on 4.2.
Edit:
On second thought, I just ran across this answer and it provides a working alternative if you can use the newer APIs (ObjectAnimator).
View view = this;
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "y", 0, 100);
anim.setDuration(super.animationDuration());
anim.start();
Where the properties of ObjectAnimator.ofFloat(view, "y", 0, 100); are
ObjectAnimator.ofFloat(Object objBeingAnimated, String propertyBeingAnimated, float startValue, float endValue)
I found this answer using ValueAnimator to modify the MarginLayoutParams.topMargin (in my case) in onAnimationUpdate(), which fixed the issue. My View starts out with its margin set so that the View is off screen.
The ObjectAnimator approach was promising but did not work for me, it had the same cutoff issue for off-screen views that I got with TranslateAnimation.

Android Progressbar: Indeterminate animation without images

I'd like to create an indeterminate animation that simply fades from one color to another (a pulse, if you will). I don't think this should require the use of images but despite my best efforts, I'm not sure I understand how to use something like AlphaAnimation with a Shape to accomplish this.
Could someone please provide some insight as to how to accomplish this? I have a feeling I'm missing something pretty straightforward here. (Examples are always appreciated!)
Thanks!
This is a trivial task in 3.0 - you can set up an ObjectAnimator to change the "color" or "backgroundColor" of an object (View, ColorDrawable, whatever has the property) between two values. See the ApiDemo animations/BouncingBalls for an example of this.
But assuming you're using pre-3.0 APIs, there are a couple of approaches. First, you could set up your own handler to give you the timing events you need, then calculate the new color at each point.
It's probably slightly easier (if not entirely intuitive) to use an AlphaAnimation. All you really want from the animation is percentage values, not to fade anything. So you don't set the animation on a view, but just set it up to run internally from a value of 0 to 1, then get the current animated value in your onDraw() method and set the current color appropriately.
For example, this will set up and start the alpha animation to run for one second:
Transformation transform = new Transformation();
AlphaAnimation anim = new AlphaAnimation(0f, 1f);
anim.setDuration(1000);
anim.start();
Then in your drawing loop, you grab the current animated value:
long time = getDrawingTime();
anim.getTransformation(time, transform);
float elapsedFraction = transform.getAlpha();
Once you have the elapsedFraction (a value between 0 and 1), you can calculate the appropriate in-between color value.
The code above may not match your situation exactly, but you should be able to do something similar to get what you want.

Categories

Resources