I'm building an app and i wanted to animate some imageView element. The problem is that at the end of the animation, the element gets an unexpected boost in the y axis, instead the defined one.
I know that at the end of the animation process the animated element returns to its original x,y. I manually added the animated offset at the onAnimationEnd method. For some odd reason the animated element jumps about 40 pixels up, and I know I didnt add it anywhere by mistake. Whats wrong here?
public class MyActivity extends Activity {
private ImageView logo,moto;
private int[] imageView_XY;
public float logoXpos,logoYpos;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.verification_activity);
logo = (ImageView) findViewById(R.id.imageView1);
//animates the logo
animate(logo,30);
}
public void animate(final ImageView imageView, int amount){
//gets the current x,y of the widget
imageView_XY = new int[2];
imageViewElement.getLocationInWindow(imageView_XY);
logoXpos = (int) imageViewElement.getX();
logoYpos = imageView_XY[1];
Log.d("Animation XY: "," current location "+"("+logoXpos+","+logoYpos+")"); //prints out 0,0
//animates the widget 100 px up
TranslateAnimation anim = new TranslateAnimation(0,0,0,-amount);
logoAnim.setDuration(1000);
logoAnim.setFillAfter(false);
logoAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
Log.d("Animation: ","animation ended");
logoXpos = imageView_XY[0];
logoYpos = imageView_XY[1];
Log.d("Animation ended XY: "," current location "+"("+logoXpos+","+logoYpos+")"); //prints out 0,0 again
imageViewElement.setY(logoYpos+30);
}
#Override
public void onAnimationRepeat(Animation animation) {
Log.d("Animation: ","animation repeat");
}
});
imageViewElement.startAnimation(anim);
}
OK I got this working. For future googlers:
I ended up setting the logoAnim.setFillAfter(false); to true and got rid of the manual shift at the end of the animation imageViewElement.setY(logoYpos+30);.
Related
Using Rotate Animation in android, but no rotation in image after clicking the button.
public class MainActivity extends AppCompatActivity {
ImageView spinImage;
Button buton;
Random r;
int degree =0 , degreeold= 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buton = (Button) findViewById(R.id.spinbutton);
spinImage= (ImageView) findViewById(R.id.spinimage);
r= new Random();
buton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
degreeold = degree % 360;
degree = r.nextInt(3600)+720;
degree= 4400;
RotateAnimation rotate = new RotateAnimation( degreeold, degree,
RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF , 0.5f);
rotate.setDuration(3600);
rotate.setFillAfter(true);
rotate.setInterpolator( new DecelerateInterpolator());
rotate.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
spinImage.setAnimation(rotate);
}
});
}
i am not able to find the mistake why there is no rotation in image. there is no error while running and app open without any delay but there is no animation when clicking the button.
You haven't started the animation. Try to use spinImage.startAnimation(rotate);
setAnimation is meant to give you more fine grained control if you want to start the animation delayed or together with other animations.
From the documentation:
Sets the next animation to play for this view. If you want the animation to play immediately, use startAnimation(android.view.animation.Animation) instead. This method provides allows fine-grained control over the start time and invalidation, but you must make sure that 1) the animation has a start time set, and 2) the view's parent (which controls animations on its children) will be invalidated when the animation is supposed to start.
Replace spinImage.setAnimation(rotate); with spinImage.startAnimation(rotate);
Im trying to make an Imageview (a ball) move around the layout and bounce a number of times before stoping when a buttom is pressed. The probles is that although the logcat says its happening, i dont see it moving.
Here it is
public class BallPhisics {
int x =400;
int y = 0;
boolean bounceX = false;
boolean bounceY= false;
int counter =0;
ImageView object;
public BallPhisics(ImageView i){
object=i;
}
public void applyMovement() {
while (true) {
object.setLeft((int) object.getX()+x); //i know i shouldnt use pixels
Log.d("EVENT", "X moved"); Log.d("Ended",Integer.toString(object.getLeft()));
object.setBottom((int)(object.getY() + y));
Log.d("EVENT", "Y moved");
try {
Thread.sleep(1000);
Log.d("EVENT", "Time 1 used");
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
if (object.getX()<=50||(object.getRight()<=50)){
bounceX =true;
break;
}
if (object.getY()<=50||object.getTop()<=50){
bounceY=true;
break;
}
}
this.bouncing();
}
public void bouncing(){
Log.d("EVENT", "Bouncing!!");
if (bounceX&&bounceY){
x=-x;
y=-y;
}
else if (bounceX){
x=-x;
y=(int)(Math.random()*100- 50 +y);
}
else if (bounceY) {
x = (int) (Math.random() * 100 - 50 + x);
y = -y;
}
counter++;
if(counter==5){return;}
this.applyMovement();
}
And on mainActivity the onclick event.
public void StartBall (View view){
ImageView imageview=(ImageView) findViewById(R.id.imageView);
BallPhisics phisics = new BallPhisics(imageview);
Log.d("EVENT", Integer.toString(imageview.getLeft() )+" before");
phisics.applyMovement();
Log.d("EVENT",Integer.toString(imageview.getLeft())+" after" );
}
Sorry if it is a lot of reading. By the way does anyone knows the proper way of moving a view?
Thanks in advance
First of all to move a View it's probably not a good idea to use setLeft (int left) or setBottom (int bottom) because this method is meant to be called by the layout system and should not generally be called otherwise, according to the documentation.
To move a View dynamically you should take a look at LayoutParams or setX (float x) and setY (float Y), if you can limit your support to Honeycomb (API Level 11).
Regardless which one you use, you may find it difficult to achieve a smooth movement. Therefore I recommend you to use the view animation system to perform tweened animation of your ImageView.
Below you will find an example of a chain animation that moves an ImageView starting from left to right with an arbitrary y-coordinate. After each translation from one x-border to the next, the onAnimationEnd will be called and start an animation in the other direction.
public class MainActivity extends Activity {
//the ImageView you want to animate
private ImageView imageview;
private Animation mAnimation;
//The coordinates the view moved to in the last animation
private float lastX=0;
private float lastY=0;
private float secondlastY;
//Listener that implements a translate animation chain
AnimationListener animationListener=new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
float newY=(float)(Math.random()*0.75);
//this prevents that we move back to the position we came from
// to get a more natural bounce animation
while(newY<=secondlastY+0.15 && newY>=secondlastY-0.15){
newY=(float)(Math.random()*0.75);
}
if(lastX==0.75f){
//test if we are on the right border of the parent
mAnimation=newAnimation(lastX,lastY,0f,newY);
mAnimation.setAnimationListener(animationListener);
lastX=0f;
}else if(lastX==0.0f){
//test if we are on the left border of the parent
mAnimation=newAnimation(lastX,lastY,0.75f,newY);
mAnimation.setAnimationListener(animationListener);
lastX=0.75f;
}
secondlastY=lastY;
lastY=newY;
imageview.startAnimation(mAnimation);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageview=(ImageView) findViewById(R.id.imageView);
//the coordinates the first animation should move to
lastY=(float)(Math.random()*0.75);
lastX=0.75f;
mAnimation=newAnimation(0f,0f,lastX,lastY);
mAnimation.setAnimationListener(animationListener);
imageview.startAnimation(mAnimation);
}
//Method that returns a new animation with given start and end coordinates
private Animation newAnimation(float startX, float startY, float endX, float endY){
Animation mAnimation = new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_PARENT, startX,
TranslateAnimation.RELATIVE_TO_PARENT, endX,
TranslateAnimation.RELATIVE_TO_PARENT, startY,
TranslateAnimation.RELATIVE_TO_PARENT, endY );
mAnimation.setDuration(2500);
mAnimation.setRepeatCount(0);
mAnimation.setRepeatMode(Animation.REVERSE);
mAnimation.setFillAfter(true);
return mAnimation;
}
}
Note:
The translation animation is relative to the parents width and height. If you move the View all the way to x=1.0 or y=1.0 you will move parts of the view out of the parent layout. Because it's sufficient for this example I chose to set 0.75 to the max position in either direction. But you should probably set this dynamically in regards to the width and height of your ImageView and ParentLayout.
In android 5.0 i am trying to work with circular reveal animation
Problem
When i click on button to start reveal animation, on first click animation doesn't start
Second Click onwards it works normally
My Code
public class MainActivity extends ActionBarActivity {
Animator a;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View cardType = findViewById(R.id.cardtype);
cardType.setVisibility(View.GONE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
a = ViewAnimationUtils.createCircularReveal(cardType,
cardType.getWidth(),
cardType.getHeight(),
0,
cardType.getHeight() * 2)
.setDuration(2500);
a.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
cardType.setVisibility(View.VISIBLE);
}
});
a.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
cardType.setVisibility(View.GONE);
}
});
findViewById(R.id.icon_first_activity).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
a.start();
}
});
}
}}
I haven't tried your code, but I think you have a small ordering problem. I think you just need to set the cardType visible before you start the animation.
Edited to add:
... and you should be setting your button View.INVISIBLE, not View.GONE.
Here: This code works.
Edited once more to add:
Yes. Your problem is that you set the view GONE initially. That means it has 0 size. Then you use cardType.getHeight and cardType.getWidth as reveal coordinates. They are 0. You are going to want to set the view INVISIBLE, initially, and then use width/2 and height/2 as the center of the reveal.
Basically what others answers say, it's correct, but the problem is if you want visibility GONE (because your layout requires it GONE!) you have to set visibility INVISIBLE in the xml with height 0dp (and/or width 0dp as well) and programmatically set the correct LayoutParams even inside the click event it will work. For example my code:
...
expandButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//To not have empty scroll, the container is INVISIBLE with 0dp height.
//Otherwise the Reveal effect will not work at the first click.
//Here I set the parameters programmatically.
viewContainer.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
if (viewContainer.getVisibility() == View.VISIBLE) {
expandButton.animate().rotation(0f).setDuration(duration).start();
Utils.unReveal(viewContainer, 0, 0);
} else {
expandButton.animate().rotation(180f).setDuration(duration).start();
Utils.reveal(viewContainer, viewContainer.getWidth(), 0);
}
}
});
...
#TargetApi(VERSION_CODES.LOLLIPOP)
public static void reveal(final View view, int cx, int cy) {
if (!hasLollipop()) {
view.setVisibility(View.VISIBLE);
return;
}
//Get the final radius for the clipping circle
int finalRadius = Math.max(view.getWidth(), view.getHeight());
//Create the animator for this view (the start radius is zero)
Animator animator =
ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
//Make the view VISIBLE and start the animation
view.setVisibility(View.VISIBLE);
animator.start();
}
#TargetApi(VERSION_CODES.LOLLIPOP)
public static void unReveal(final View view, int cx, int cy) {
if (!hasLollipop()) {
view.setVisibility(View.GONE);
return;
}
//Get the initial radius for the clipping circle
int initialRadius = view.getWidth();
//Create the animation (the final radius is zero)
Animator animator =
ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0);
//Make the view GONE when the animation is done
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});
//Start the animation
animator.start();
}
If you set only GONE in the xml, the first time will never work because height/width/x/y/etc.. are 0. Also, if you just set INVISIBLE before the call to the animation it will not work as well, but if you start with visibility INVISIBLE it will initialize the layout params.
what i did is, Like i have two view with same height,As we now visibility gone returns 0 {height and width} than i am giving visible view height every time and its work for me.
The solution is don't get values directly into code
Either put the animation code on click and the values outside onclick
or get the values from other activity
By values i mean cardType.getWidth() and cardType.getHeight()
I've created a extension to the Animation class in order to create a background fade out animation. I start the animation after pressing a ListView row item. If I press one after another I want to cancel the first animation and start the second. But a bug that I'm having is when I press fast one row after another the animation doesn't stop. After debugging I've noticed that the applyTransformation method keeps running for the first animation. I've decided to override the cancel function, but how do I stop the transformation?
public BackgroundAnimation(View view, int color){
this.view = view;
setDuration(4000L);
red = Color.red(color);
blue = Color.blue(color);
green = Color.green(color);
}
#Override
public void applyTransformation(float interpolatedTime,Transformation t){
//super.applyTransformation(interpolatedTime, t);
view.setBackgroundColor(Color.argb((int) ((1 - interpolatedTime) * 255), red, green, blue));
}
I had the exact same problem, interpolatedTime would run 0 -> 1 then infinitely repeat for 0. My solution was to clearAnimation in an AnimationListener. It doesn't seem like you should have to do this, but oh well.
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
animationTarget.clearAnimation();
}
#Override
public void onAnimationRepeat(Animation animation) {}
});
I would like to apply successive animations (say ScaleAnimation) to an ImageView showing a resource image. The animation is triggered by a button. For example, I would like to incrementally enlarge an image upon each button click.
I've set fillAfter="true" on the animation. However, all the animations start from the original state of the ImageView. It seems as if the ImageView resets its state and the animation is always the same, instead of starting from the final state of the previous animation.
What am I doing wrong?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button)findViewById(R.id.Button01);
button.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
animate();
}});
}
private void animate() {
ImageView imageView = (ImageView) findViewById(R.id.ImageView01);
ScaleAnimation scale = new ScaleAnimation((float)1.0, (float)1.5, (float)1.0, (float)1.5);
scale.setFillAfter(true);
scale.setDuration(500);
imageView.startAnimation(scale);
}
It seems as if the ImageView resets
its state and the animation is always
the same, instead of starting from the
final state of the previous animation.
Precisely! I'm sure there's a use for fillAfter="true", but I haven't figured out the point for it yet.
What you need to do is set up an AnimationListener on each Animation of relevance, and do something in the listener's onAnimationEnd() to actually persist the end state of your animation. I haven't played with ScaleAnimation so I'm not quite sure what the way to "persist the end state" would be. If this were an AlphaAnimation, going from 1.0 to 0.0, you would make the widget INVISIBLE or GONE in onAnimationEnd(), for example.
I've had the same problem and created the following code to easily use different animations. It only supports translation and alpha levels for now as I haven't used scaling, but could easily be extended to support more features.
I reset the scroll and the visibility before starting the animation, but that's just because I needed on/off animations.
And the "doEnd" boolean is there to avoid a stack overflow on the recursion (scrollTo calls onAnimationEnd for some obscure reason...)
private void setViewPos(View view, Animation anim, long time){
// Get the transformation
Transformation trans = new Transformation();
anim.getTransformation(time, trans);
// Get the matrix values
float[] values = new float[9];
Matrix m = trans.getMatrix();
m.getValues(values);
// Get the position and apply the scroll
final float x = values[Matrix.MTRANS_X];
final float y = values[Matrix.MTRANS_Y];
view.scrollTo(-(int)x, -(int)y);
// Show/hide depending on final alpha level
if (trans.getAlpha() > 0.5){
view.setVisibility(VISIBLE);
} else {
view.setVisibility(INVISIBLE);
}
}
private void applyAnimation(final View view, final Animation anim){
view.scrollTo(0, 0);
view.setVisibility(VISIBLE);
anim.setAnimationListener(new AnimationListener(){
private boolean doEnd = true;
#Override
public void onAnimationEnd(Animation animation) {
if (doEnd){
doEnd = false;
setViewPos(view, animation, anim.getStartTime() + anim.getDuration());
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
});
view.startAnimation(anim);
}