I want to build an animation of TextViews, which repeats itself just after completion.
For each View I want to animate, I use the following piece of code
final float oldX = v.getX();
final float newX = v.getX() - (float)totalWidth;
final AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
v.setX(oldX);
animFinished = true;
//This line won't compile
//v.animate().setDuration(animDuration).setInterpolator(newsInterpolator)
// .setListener(listener).x(newX);
}
};
v.animate().setDuration(animDuration).setInterpolator(newsInterpolator)
.setListener(listener).x(newX);
I tried to place the last piece of code into the onAnimationEnd, but Java will not compile since it considers the object listener as not initialized. Moreover, I don't think that this "recursive" animation invocation is a good solution, it was the first thing which came to my mind. I am suspicious that there is a simple and sound way to implement looping property animation, but I failed to locate it, so I turned here for help.
Thanks in advance
Well, I am going to answer myself again.
TranslateAnimation class has methods about repeating the animation, so I used it instead of ViewPropertyAnimator.
The following code seems to work:
long duration = 1000* ((long)totalWidth / newsScrollSpeed);
System.out.println("totalWidth="+totalWidth);
TranslateAnimation anim = new TranslateAnimation(0,-totalWidth,0,0);
anim.setInterpolator(linearInterpolator);
anim.setDuration(duration);
anim.setRepeatCount(TranslateAnimation.INFINITE);
anim.setRepeatMode(TranslateAnimation.RESTART);
for(i=0;i<this.getChildCount();i++)
{
View v = this.getChildAt(i);
if(v.getId() == R.id.yuruyen_yazi)
{
continue;
}
v.startAnimation(anim);
}
Not elegant way, but it works:
Runnable runnable = new Runnable() {
#Override
public void run() {
// update newX
v.animate().setDuration(animDuration).setInterpolator(newsInterpolator).x(newX).withEndAction(this).start();
}
};
v.animate().setDuration(animDuration).setInterpolator(newsInterpolator).x(newX).withEndAction(runnable).start();
Related
I am using the circular reveal animation in my project, but it is now working correctly. The problem is the reveal happens way to fast and you almost can't see the reveal because it expands like instantly. I tried setting anim.setDuration() but that did not change anything. I used the code from the google examples.
Here my code:
View myView = getActivity().findViewById(R.id.view_to_expand);
int cx = myView.getRight();
int cy = myView.getBottom();
int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
myView.setVisibility(View.VISIBLE);
anim.start();
view_to_expand is a simple relativelayout, don't think the problem is there. Also how can I apply the circular reveal to animation transitions?
The instantaneous expansion is because there is some other heavy work on main thread aside from your animation (data update, other views/fragments hiding, render refresh and so on).
Best bet is to wrap it into a runnable and add it to the stack. It will be called when there is available CPU cycle and will show your animation.
Below is the right way to create and use your runnable. Try not to post an anonymous one since there is possibility user to return and your runnable to hang and expose a memory leak and/or to throw a runtime exception.
I presume here your class where your view stays is an activity and your myView is an instance reference in your activity
public final ApplicationActivity extends Activity {
private View myView;
private final Runnable revealAnimationRunnable = new Runnable() {
#Override
public void run() {
int cx = myView.getRight();
int cy = myView.getBottom();
int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
Animator animator = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
animator.start();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
...
myView = findViewById(R.id.view_to_expand);
myView.setVisibility(View.VISIBLE);
myView.post(revealAnimationRunnable);
// alternatively, in case load is way too big, you can post with delay
// i.e. comment above line and uncomment the one below
// myView.postDelayed(revealAnimationRunnable, 200);
}
#Override
protected void onDestroy() {
...
myView.removeCallbacks(revealAnimationRunnable);
}
}
I'm trying to implement a Blink Animation.
This code makes a view to blink fade in and fade out:
AlphaAnimation blink = new AlphaAnimation(0.0f, 1.0f);
blink.setDuration(500);
blink.setStartOffset(0);
//changing it makes more than one animation appear in different time stamps.
blink.setRepeatMode(Animation.REVERSE);
blink.setRepeatCount(Animation.INFINITE);
I have two issues:
setStartOffset(n); --> Changing n makes more than one animation appear in different time stamps. Not synced. I want it to be synced, all animations should appear and dissappear at same time.
I do not want fade in or fade out, simply visible & gone with few millisecond delay.
Is there any other Class of Animation that i had to use, or i had to make a custom animation.
Pls. help.
For animation without the fading you can create your own custom Interpolator:
import android.view.animation.Interpolator;
public class StepInterpolator implements Interpolator {
float mDutyCycle;
public StepInterpolator(float dutyCycle) {
mDutyCycle = dutyCycle;
}
#Override
public float getInterpolation(float input) {
return input < mDutyCycle ? 0 : 1;
}
}
Then set the interpolator in the Animation object:
blink.setInterpolator(new StepInterpolator(0.5f));
So, my answer ... it's a class that toggles visibility of a view in a certain interval. Of course it can be solved differently, maybe you get some inspiration...
public static class ViewBlinker {
private Handler handler = new Handler();
private Runnable blinker;
public ViewBlinker(final View v, final int interval) {
this.blinker = new Runnable() {
#Override
public void run() {
v.setVisibility(v.getVisibility()==View.VISIBLE?View.INVISIBLE:View.VISIBLE);
handler.postDelayed(blinker, interval);
}
};
}
public void startBlinking() {
handler.post(blinker);
}
public void stopBlinking() {
handler.removeCallbacks(blinker);
}
}
and you use it like this :
ViewBlinker blinker = new ViewBlinker(YOUR_BLINK_VIEW, YOUR_BLINK_INTERVAL);
blinker.startBlinking();
and when your view is finished blinking, call
blinker.stopBlinking();
Actually, based on cold ash's answer in 2014, all of his/her code can be simplified as below (thanks to lambda):
blink.setInterpolator(input -> input < 0.5f ? 0 : 1);
Yes, just a single line. Very simple.
i want to animate button(ie; rotation, translation) then change the text of a button. unfortunately, it always first changes the text of the button then do the animation.
How can I achieve my goal?
Pls help me
my code is like this;
AnimationSet set = new AnimationSet(true);
Animation anim1 = new RotateAnimation(0, 360, 500, 750);
anim1.setDuration(3000);
anim1.setFillAfter(true);
set.addAnimation(anim1);
Animation anim2 = new RotateAnimation(0, 360, 1024, 824);
anim2.setDuration(3000);
anim2.setFillAfter(true);
set.addAnimation(anim2);
anim2.setStartOffset(3000);
first.clearAnimation();
set.setFillAfter(true);
first.startAnimation(set);
numbers[0]=min + (int)(Math.random() * ((max - min) + 1));
Your code starts the animation but is not blocking : once the animation is started, the program goes on.
You could try getting an handler and post the change text event at the right time :
Handler mHandler=new Handler();
Runnable lRunnable =new Runnable()
{
public void run()
{
//Your change text code
}
};
mHandler.postDelayed(lRunnable , 3000); // Or any other duration so you have the right effect
A better solution is to add an AnimationListener to the animation, or if you are on JB use the view property animators and the withEndAction() method. You should avoid the old animation framework if possible. It doesn't actually change the properties, it just draw the view with a transformation.
set.setAnimationListener(new AnimationListener() {
public void onAnimationEnd() {
// ...
}
public void onAnimationStart() {
}
public void onAnimationRepeat() {
}
}
But I recommend the view property animations if you can use them. They are much better to work with.
I know multiple ways to get location values of a View.
getLocationOnScreen()
getLocationInWindow()
getLeft()
However, none of them actually returns the current location of the View I moved by startAnimation() method, but only the original location.
So, now let's make a View that moves to the right by 10 pixels on each Click (I'm omitting the layout, since you can just place whatever view in your main XML and give it onClickListener).
public class AndroidTestActivity extends Activity implements OnClickListener {
LinearLayout testView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
testView = (LinearLayout) this.findViewById(R.id.test);
testView.setOnClickListener(this);
}
public void onClick(View v) {
int[] pLoS = new int[2];
testView.getLocationOnScreen(pLoS);
TranslateAnimation move = new TranslateAnimation(pLoS[0], pLoS[0] + 10, 0f, 0f);
move.setFillAfter(true);
move.setFillEnabled(true);
testView.startAnimation(move);
}
}
As you see, this doesn't work as I intended, since getLocationOnScreen() always returns the same value (in my case, 0), and doen't reflect the value I used in TranslateAnimation...
Any idea?
Assuming you're using Android < 3.0 then your question may be in a similar vein to mine I asked here. Basically Animations are separate from the View itself i.e. Android animates a copy of your View. That is why getLocationOnScreen() always returns 0. It's not the view that has moved (animated) it was the copy that moved (animated). If you see the answers to my question this issue has been addressed in later versions of Android.
Well, if you are trying to see how many pixels the view has shifted during/after its animation, then you can open up the Transformation object on the animation.
Here's an example using the AnimationListener:
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
Transformation trans = new Transformation();
// startTime + duration = end of animation
int endTime = animation.getStartTime()+animation.getDuration();
animation.getTransformation(endTime, trans);
Matrix transformationMatrix = trans.getMatrix();
float[] matrixVals = new float[9];
transformationMatrix.getValues(matrixVals);
float xTraveled = matrixVals[2];
float yTraveled = matrixVals[5];
// do something with them here...
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
I may not be exactly correct in the array indices for these, definitely use Matrix.toString() and look at the values yourself. xTraveled and yTraveled will give you the amount of distance traveled by the TranslateAnimation at the indicated time (in this case, at the end of the animation).
animations on android gingerbread and below do not really change the view in any way , only change the way it is shown.
the only way to get the new position is by calculating it.
The question is "How do i scroll up a ScrollView to top very smoothly and slowly".
In my special case i need to scroll to top in about 1-2 seconds.
Ive tried interpolating manually using a Handler (calling scrollTo(0, y)) but that didnt work at all.
I've seen this effect on some bookreader-apps yet, so there must be a way, im sure :D.
(Text is very slowly scrolling up to go on reading without touching the screen, doing input).
I did it using object animator (Available in API >= 3) and it looks very good:
Define an ObjectAnimator:
final ObjectAnimator animScrollToTop = ObjectAnimator.ofInt(this, "scrollY", 0);
(this refers to the class extending Android's ScrollView)
you can set its duration as you wish:
animScrollToTop.setDuration(2000); (2 seconds)
P.s. Don't forget to start the animation.
In 2 seconds move the scroll view to the possition of 2000
new CountDownTimer(2000, 20) {
public void onTick(long millisUntilFinished) {
scrollView.scrollTo(0, (int) (2000 - millisUntilFinished)); // from zero to 2000
}
public void onFinish() {
}
}.start();
Try the following code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
ValueAnimator realSmoothScrollAnimation =
ValueAnimator.ofInt(parentScrollView.getScrollY(), targetScrollY);
realSmoothScrollAnimation.setDuration(500);
realSmoothScrollAnimation.addUpdateListener(new AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator animation)
{
int scrollTo = (Integer) animation.getAnimatedValue();
parentScrollView.scrollTo(0, scrollTo);
}
});
realSmoothScrollAnimation.start();
}
else
{
parentScrollView.smoothScrollTo(0, targetScrollY);
}
Have you tried smoothScrollTo(int x, int y)?
You can't set the speed parameter but maybe this function will be ok for you
You could use the Timer and TimerTask class. You could do something like
scrollTimer = new Timer();
scrollerSchedule = new TimerTask(){
#Override
public void run(){
runOnUiThread(SCROLL TO CODE GOES HERE);
}
};
scrollTimer.schedule(scrollerSchedule, 30, 30);