I have an ImageView and a RecyclerView at top and bottom of an Activity respectively.
ImageView can be dragged and dropped in any positions in the RecyclerView, which works fine.
What I would like to do next is that to automate the drag and drop animation when I tapped on RecyclerView items.
Is there any way to create the drag and drop animation without actually doing it with ImageView and clicked item position.
Adapter -
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dragLocation.onAutoDragStart(holder.getAdapterPosition(),view);
holder.root.setBackground(mContext.getResources().getDrawable(R.drawable.envoy_orange_corner));
}
});
Activity -
#Override
public void onAutoDragStart(int position, View view) {
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(mRlAvatar);
mRlAvatar.startDrag(data, shadowBuilder, mRlAvatar, 0);
//code for drag and drop animation
// mRlAvatar.animate()
// .x(view.getX())
// .y(view.getY())
// .setDuration(1000)
// .start();
}
Added a FrameLayout in activiy layout then avatar view cloned to the exact position and animated to RecyclerView item coordinates on long tap.
#Override
public void onAutoDragStart(int position, View view) {
int[] originalPos = new int[2];
view.getLocationInWindow(originalPos);
final int x = originalPos[0];
final int y = originalPos[1];
int[] originalPosA = new int[2];
mRlAvatar.getLocationInWindow(originalPosA);
final int xA = originalPosA[0];
final int yA = originalPosA[1];
final View avatarView = LayoutInflater.from(this).inflate(R.layout.avatar_view, null);
avatarView.setX(xA);
avatarView.setY(yA);
((FrameLayout) findViewById(R.id.base_frame)).addView(avatarView);
avatarView.animate().x(x).y(y).setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
((FrameLayout) findViewById(R.id.base_frame)).removeView(avatarView);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
Related
I have
Layout Game (Relative Layout)
ImageView (The Player)
ViewPropertyAnimator (The Animation)
My Code is:
final Vibrator vibe = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
final ImageView playerImageView = (ImageView) layoutInflater.inflate(R.layout.player, null);
playerImageView.setLayoutParams(new RelativeLayout.LayoutParams(playerSizeX, playerSizeY));
playerImageView.setImageDrawable(playerDrawable);
playerImageView.setX(playerVisualPositionX);
playerImageView.setY(playerVisualPositionY);
playerImageView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
vibe.vibrate(100);
touchedPlayer();
}
return true;
}
});
layoutGame.addView(playerImageView);
ViewPropertyAnimator viewPropertyAnimator = playerImageView.animate();
viewPropertyAnimator.x(positionAnimateX); // The view will be animated such that it moves to positionAnimateX.
viewPropertyAnimator.y(positionAnimateY); // The view will be animated such that it moves to positionAnimateY.
viewPropertyAnimator.setDuration(animationTime);
viewPropertyAnimator.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
//super.onAnimationEnd(animation);
layoutGame.removeView(playerImageView);
if (!gameOver && !gamePaused) {
addNewPlayer();
}
}
#Override
public void onAnimationStart(Animator animation) {
//super.onAnimationStart(animation);
currentAnimation = animation;
}
});
Sometimes I touch on the Player but onClicListener on ImageView is not called/fired method touchedPlayer() during animation. Do you know what it can be?
Try using an ObjectAnimator instead to animate X and Y for your view, I never experienced such problems and I use it a lot for stuff similar to what you're doing here.
Try this and see if it works:
layoutGame.addView(playerImageView);
PropertyValuesHolder xHolder = PropertyValuesHolder.ofFloat("X", playerImageView.getX(), positionAnimateX); // The view will be animated such that it moves to positionAnimateX.
PropertyValuesHolder yHolder = PropertyValuesHolder.ofFloat("Y", playerImageView.getY(), positionAnimateY); // The view will be animated such that it moves to positionAnimateY.
ValueAnimator valueAnimator = ObjectAnimator.ofPropertyValuesHolder(playerImageView, xHolder, yHolder);
valueAnimator.setDuration(animationTime);
valueAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
//super.onAnimationStart(animation);
currentAnimation = animation;
}
#Override
public void onAnimationEnd(Animator animation) {
//super.onAnimationEnd(animation);
layoutGame.removeView(playerImageView);
if (!gameOver && !gamePaused) {
addNewPlayer();
}
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.start();
I'm creating a Q&A where each question is a card. The answer starts showing the first line, but when its clicked it should expanded to show the full answer.
When an answer is expanded/collapsed the rest of the RecyclerView should animate to make room for the expansion or collapse to avoid showing a blank space.
I watched the talk on RecyclerView animations, and believe I want a custom ItemAnimator, where I override animateChange. At that point I should create an ObjectAnimator to animate the height of the View's LayoutParams. Unfortunately I'm having a hard time tying it all together. I also return true when overriding canReuseUpdatedViewHolder, so we reuse the same viewholder.
#Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}
#Override
public boolean animateChange(#NonNull RecyclerView.ViewHolder oldHolder,
#NonNull final RecyclerView.ViewHolder newHolder,
#NonNull ItemHolderInfo preInfo,
#NonNull ItemHolderInfo postInfo) {
Log.d("test", "Run custom animation.");
final ColorsAdapter.ColorViewHolder holder = (ColorsAdapter.ColorViewHolder) newHolder;
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) holder.tvColor.getLayoutParams();
ObjectAnimator halfSize = ObjectAnimator.ofInt(holder.tvColor.getLayoutParams(), "height", params.height, 0);
halfSize.start();
return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
}
Right now I'm just trying to get something to animate, but nothing happens... Any ideas?
I think your animation was not working because you cannot animate LayoutParams that way although it would be neat if you could. I tried the code you had and all it did was make my view jump to the new height. Only way I found to get this to work was to use a ValueAnimator as you can see in the example below.
I noticed some shortcomings when using the DefaultItemAnimator to show/hide a view by updating its visibility. Although it did make room for the new view and animated the rest of the items up and down based on the visibility of the expandable view, I noticed it did not animate the height of the expandable view. It simply faded into place and out of place using alpha value only.
Below is a custom ItemAnimator that has size and alpha animations based on hiding/showing a LinearLayout in the ViewHolder layout. It also allows the reuse of the same ViewHolder and attempts handling partial animations correctly if the user taps the header quickly:
public static class MyAnimator extends DefaultItemAnimator {
#Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}
private HashMap<RecyclerView.ViewHolder, AnimatorState> animatorMap = new HashMap<>();
#Override
public boolean animateChange(#NonNull RecyclerView.ViewHolder oldHolder, #NonNull final RecyclerView.ViewHolder newHolder, #NonNull ItemHolderInfo preInfo, #NonNull ItemHolderInfo postInfo) {
final ValueAnimator heightAnim;
final ObjectAnimator alphaAnim;
final CustomAdapter.ViewHolder vh = (CustomAdapter.ViewHolder) newHolder;
final View expandableView = vh.getExpandableView();
final int toHeight; // save height for later in case reversing animation
if(vh.isExpanded()) {
expandableView.setVisibility(View.VISIBLE);
// measure expandable view to get correct height
expandableView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
toHeight = expandableView.getMeasuredHeight();
alphaAnim = ObjectAnimator.ofFloat(expandableView, "alpha", 1f);
} else {
toHeight = 0;
alphaAnim = ObjectAnimator.ofFloat(expandableView, "alpha", 0f);
}
heightAnim = ValueAnimator.ofInt(expandableView.getHeight(), toHeight);
heightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
expandableView.getLayoutParams().height = (Integer) heightAnim.getAnimatedValue();
expandableView.requestLayout();
}
});
AnimatorSet animSet = new AnimatorSet()
.setDuration(getChangeDuration());
animSet.playTogether(heightAnim, alphaAnim);
animSet.addListener(new Animator.AnimatorListener() {
private boolean isCanceled;
#Override
public void onAnimationStart(Animator animation) { }
#Override
public void onAnimationEnd(Animator animation) {
if(!vh.isExpanded() && !isCanceled) {
expandableView.setVisibility(View.GONE);
}
dispatchChangeFinished(vh, false);
animatorMap.remove(newHolder);
}
#Override
public void onAnimationCancel(Animator animation) {
isCanceled = true;
}
#Override
public void onAnimationRepeat(Animator animation) { }
});
AnimatorState animatorState = animatorMap.get(newHolder);
if(animatorState != null) {
animatorState.animSet.cancel();
// animation already running. Set start current play time of
// new animations to keep them smooth for reverse animation
alphaAnim.setCurrentPlayTime(animatorState.alphaAnim.getCurrentPlayTime());
heightAnim.setCurrentPlayTime(animatorState.heightAnim.getCurrentPlayTime());
animatorMap.remove(newHolder);
}
animatorMap.put(newHolder, new AnimatorState(alphaAnim, heightAnim, animSet));
dispatchChangeStarting(newHolder, false);
animSet.start();
return false;
}
public static class AnimatorState {
final ValueAnimator alphaAnim, heightAnim;
final AnimatorSet animSet;
public AnimatorState(ValueAnimator alphaAnim, ValueAnimator heightAnim, AnimatorSet animSet) {
this.alphaAnim = alphaAnim;
this.heightAnim = heightAnim;
this.animSet = animSet;
}
}
}
This is the result using a slightly modified RecyclerView demo.
Update:
Just noticed your use case is actually a bit different after rereading the question. You have a text view and only want to show a single line of it and then later expand it to show all lines. Fortunately that simplifies the custom animator:
public static class MyAnimator extends DefaultItemAnimator {
#Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}
private HashMap<RecyclerView.ViewHolder, ValueAnimator> animatorMap = new HashMap<>();
#Override
public boolean animateChange(#NonNull RecyclerView.ViewHolder oldHolder, #NonNull final RecyclerView.ViewHolder newHolder, #NonNull ItemHolderInfo preInfo, #NonNull ItemHolderInfo postInfo) {
ValueAnimator prevAnim = animatorMap.get(newHolder);
if(prevAnim != null) {
prevAnim.reverse();
return false;
}
final ValueAnimator heightAnim;
final CustomAdapter.ViewHolder vh = (CustomAdapter.ViewHolder) newHolder;
final TextView tv = vh.getExpandableTextView();
if(vh.isExpanded()) {
tv.measure(View.MeasureSpec.makeMeasureSpec(((View) tv.getParent()).getWidth(), View.MeasureSpec.AT_MOST), View.MeasureSpec.UNSPECIFIED);
heightAnim = ValueAnimator.ofInt(tv.getHeight(), tv.getMeasuredHeight());
} else {
Paint.FontMetrics fm = tv.getPaint().getFontMetrics();
heightAnim = ValueAnimator.ofInt(tv.getHeight(), (int)(Math.abs(fm.top) + Math.abs(fm.bottom)));
}
heightAnim.setDuration(getChangeDuration());
heightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
tv.getLayoutParams().height = (Integer) heightAnim.getAnimatedValue();
tv.requestLayout();
}
});
heightAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
dispatchChangeFinished(vh, false);
animatorMap.remove(newHolder);
}
#Override
public void onAnimationCancel(Animator animation) { }
#Override
public void onAnimationStart(Animator animation) { }
#Override
public void onAnimationRepeat(Animator animation) { }
});
animatorMap.put(newHolder, heightAnim);
dispatchChangeStarting(newHolder, false);
heightAnim.start();
return false;
}
}
And the new demo:
You don't have to implement a custom ItemAnimator the default DefaultItemAnimator already supports what you need. However you need to tell this Animator which views changed. I guess you are calling notifyDataSetChanged() in your adapter. This prevents the animation for a single changed item in the RecyclerView (in your case the expand/collapse of the item).
You should use notifyItemChanged(int position) for the items that were changed. Here is a short itemClicked(int position) method that expands/collapses views in the RecyclerView. The field expandedPosition keeps track of the currently expanded item:
private void itemClicked(int position) {
if (expandedPosition == -1) {
// selected first item
expandedPosition = position;
notifyItemChanged(position);
} else if (expandedPosition == position) {
// collapse currently expanded item
expandedPosition = -1;
notifyItemChanged(position);
} else {
// collapse previously expanded item and expand new item
int oldExpanded = expandedPosition;
expandedPosition = position;
notifyItemChanged(oldExpanded);
notifyItemChanged(position);
}
}
This is the result:
According the documentation, you need to return false in animateChange or call runPendingAnimations later. Try returning false.
http://developer.android.com/reference/android/support/v7/widget/RecyclerView.ItemAnimator.html
Try this class:
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Paint;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.TextView;
/**
* Created by ankitagrawal on 2/14/16.
*/
public class AnimatedViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
private int originalHeight = 0;
private boolean mIsViewExpanded = false;
private TextView textView;
// ..... CODE ..... //
public AnimatedViewHolder(View v) {
super(v);
v.setOnClickListener(this);
// Initialize other views, like TextView, ImageView, etc. here
// If isViewExpanded == false then set the visibility
// of whatever will be in the expanded to GONE
if (!mIsViewExpanded) {
// Set Views to View.GONE and .setEnabled(false)
textView.setLines(1);
}
}
#Override
public void onClick(final View view) {
// Declare a ValueAnimator object
ValueAnimator valueAnimator;
if(mIsViewExpanded) {
view.measure(View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.AT_MOST), View.MeasureSpec.UNSPECIFIED);
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(view.getHeight(), view.getMeasuredHeight());
} else {
Paint.FontMetrics fm = ((TextView)view).getPaint().getFontMetrics();
valueAnimator = ValueAnimator.ofInt(view.getHeight(), (int) (Math.abs(fm.top) + Math.abs(fm.bottom)));
mIsViewExpanded = true;
}
valueAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) { }
#Override
public void onAnimationStart(Animator animation) { }
#Override
public void onAnimationRepeat(Animator animation) { }
});
valueAnimator.setDuration(200);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
view.getLayoutParams().height = (Integer) animation.getAnimatedValue();
view.requestLayout();
}
});
valueAnimator.start();
}
}
The Advantage of this approach is it only add animation to onClick event and that best suits your requirement.
adding animation to viewholder will be too burdensome to your requirement.
and itemAnimator as per doc are animation for layout out items so also not best suits your requirement.
For expand & collapse animation android there is github library for it.
ExpandableRecyclerView
1).Add dependencies in the build.gradle file
dependencies {
compile 'com.android.support:recyclerview-v7:22.2.0'
compile 'com.bignerdranch.android:expandablerecyclerview:1.0.3'
}
Image of Expand & Collapse Animation
2) Expand & Collapse animation for RecyclerView animation
public static class ExampleViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
private int originalHeight = 0;
private boolean isViewExpanded = false;
private YourCustomView yourCustomView
public ExampleViewHolder(View v) {
super(v);
v.setOnClickListener(this);
// Initialize other views, like TextView, ImageView, etc. here
// If isViewExpanded == false then set the visibility
// of whatever will be in the expanded to GONE
if (isViewExpanded == false) {
// Set Views to View.GONE and .setEnabled(false)
yourCustomView.setVisibility(View.GONE);
yourCustomView.setEnabled(false);
}
}
#Override
public void onClick(final View view) {
// If the originalHeight is 0 then find the height of the View being used
// This would be the height of the cardview
if (originalHeight == 0) {
originalHeight = view.getHeight();
}
// Declare a ValueAnimator object
ValueAnimator valueAnimator;
if (!mIsViewExpanded) {
yourCustomView.setVisibility(View.VISIBLE);
yourCustomView.setEnabled(true);
mIsViewExpanded = true;
valueAnimator = ValueAnimator.ofInt(originalHeight, originalHeight + (int) (originalHeight * 2.0)); // These values in this method can be changed to expand however much you like
} else {
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(originalHeight + (int) (originalHeight * 2.0), originalHeight);
Animation a = new AlphaAnimation(1.00f, 0.00f); // Fade out
a.setDuration(200);
// Set a listener to the animation and configure onAnimationEnd
a.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
yourCustomView.setVisibility(View.INVISIBLE);
yourCustomView.setEnabled(false);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
// Set the animation on the custom view
yourCustomView.startAnimation(a);
}
valueAnimator.setDuration(200);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
view.getLayoutParams().height = value.intValue();
view.requestLayout();
}
});
valueAnimator.start();
}
}
Hope this will help you.
I'm trying to create a simple slide in animation for an existing recycler view.
Lets say the recycler holds 50 items, at some point the dataset has change and now contains only 40 items, the items have been replaced, all the previous 50 items are not relevant anymore.
So, notifyDatasetChanged() is being called after the data structure has been modified and the new items are animated in.
The problem is you can still see the previous 40 items below the new items, on the same space of each cell, you see both the previous data and the new data.
the code for ItemAnimator subclass is below, if I add a remove animation that changes the opacity of the remove cell it will be invisible but the item decoration (list lines) are not removed, I would prefer to remove the items entirely and not make it invisible.
public class RVSlideAnimation extends RecyclerView.ItemAnimator {
List<RecyclerView.ViewHolder> mViewHolders = new ArrayList<RecyclerView.ViewHolder>();
#Override
public void runPendingAnimations() {
if (!mViewHolders.isEmpty()) {
int animationDuration = 250;
AnimatorSet animator;
View target;
for (final RecyclerView.ViewHolder viewHolder : mViewHolders) {
target = viewHolder.itemView;
target.setPivotX(target.getMeasuredWidth() / 2);
target.setPivotY(target.getMeasuredHeight() / 2);
animator = new AnimatorSet();
animator.playTogether(
ObjectAnimator.ofFloat(target, "translationX", target.getMeasuredWidth(), 0.0f),
ObjectAnimator.ofFloat(target, "alpha", target.getAlpha(), 1.0f)
);
animator.setTarget(target);
animator.setDuration(animationDuration);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setStartDelay((animationDuration * viewHolder.getAdapterPosition()) / 10);
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
mViewHolders.remove(viewHolder);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.start();
}
}
}
#Override
public boolean animateRemove(RecyclerView.ViewHolder viewHolder) {
//viewHolder.itemView.animate().alpha(0).setDuration(100);
return false;
}
#Override
public boolean animateAdd(RecyclerView.ViewHolder viewHolder) {
viewHolder.itemView.setAlpha(0.0f);
return mViewHolders.add(viewHolder);
}
#Override
public boolean animateMove(RecyclerView.ViewHolder viewHolder, int i, int i2, int i3, int i4) {
return false;
}
#Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
return false;
}
#Override
public void endAnimation(RecyclerView.ViewHolder viewHolder) {
}
#Override
public void endAnimations() {
}
#Override
public boolean isRunning() {
return !mViewHolders.isEmpty();
}
}
recyclerView.destroyDrawingCache(); before notifyDatasetChaged() solved the issue for me.
I want to play one animation with multiple views in android.
This is the simplified example of code.
This code works incorrectly.
Every startAnimation() call, affects all previously animated views
Please tell me, why it doesn't works and how to make it properly.
public SomeClass() {
private int currentViewID = 0;
private View[] views = { view1, view2, view3, view4, view5 }
private Animation anim = AnimationUtils.loadAnimation(this.getContext(), android.R.anim.fade_out);
public SomeClass() {
this.anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
if (SomeClass.this.currentViewID != SomeClass.this.views.length) SomeClass.this.hideNextView();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
});
this.hideNextView();
}
private void hideNextView() {
this.views[this.currentViewID++].startAnimation(this.anim);
}
}
If you don't want to deal with many Animations in your class (one for each View) you could do things locally:
private int currentViewID = 0;
private View[] views = { view1, view2, view3, view4, view5 }
public SomeClass() {
this.hideNextView();
}
private void hideNextView() {
final Animation anim = AnimationUtils.loadAnimation(this.getContext(), android.R.anim.fade_out);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
if (SomeClass.this.currentViewID != SomeClass.this.views.length) SomeClass.this.hideNextView();
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationStart(Animation animation) {}
});
this.views[this.currentViewID++].startAnimation(anim);
}
I have several ImageViews in a RelativeLayout.
When the user taps any of the ImageViews, I want the ImageView to be moved to a specified location using a subtle animation.
Eg; I have initially set margins for LayoutParams associated with an ImageView as layoutparams1.setMargins(90,70,0,0); and I have then added it to the layout.
When the ImageView is tapped, I'd like its new location to be 200,200, done with animation.
So, is it possible? if yes, then how?
Note that I have both RelativeLayout and all of its child ImageViews created programmatically.
And I'm new to Android development so an elaborative answer is expected.
TranslateAnimation animation = new TranslateAnimation(0, 50, 0, 100);
animation.setDuration(1000);
animation.setFillAfter(false);
animation.setAnimationListener(new MyAnimationListener());
imageView.startAnimation(animation);
UPDATE :
The problem is that the View is actually still in it's old position. So we have to move it when the animation is finished. To detect when the animation is finished we have to create our own animationListener (inside our activity class):
private class MyAnimationListener implements AnimationListener{
#Override
public void onAnimationEnd(Animation animation) {
imageView.clearAnimation();
LayoutParams lp = new LayoutParams(imageView.getWidth(), imageView.getHeight());
lp.setMargins(50, 100, 0, 0);
imageView.setLayoutParams(lp);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
}
So the onClickEvent will get fired again at it's new place.
The animation will now move it even more down, so you might want to save the x and y in a variable, so that in the onAnimationEnd() you move it not to a fix location.
It is better to use ObjectAnimator which actually moves the ImageView to the new position.
E.g.:
ImageView splash;
#Override
public boolean onTouchEvent(MotionEvent event) {
float tx = event.getX();
float ty = event.getY();
int action = event.getAction();
switch(action) {
case MotionEvent.ACTION_DOWN:
tx = event.getX();
ty = event.getY();
// findViewById(R.id.character).setX(tx-45);
// findViewById(R.id.character).setY(ty-134);
ObjectAnimator animX = ObjectAnimator.ofFloat(splash, "x", tx-45);
ObjectAnimator animY = ObjectAnimator.ofFloat(splash, "y", ty-134);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
break;
default:
}
return true;
}
you can use this code
imageView.animate().x(80).y(212).setDuration(300);
or
for soft animation you can use this library
https://github.com/wirecube/android_additive_animations
In below code I am adding a image view in center on frame layout dynamically. After add I am increase scaling and set alpha to give zoom effect and after complete animation I am just translate my image view one position to another position.
Add image view on framelayout
imgHeart = new ImageView(getBaseContext());
imgHeart.setId(R.id.heartImage);
imgHeart.setImageResource(R.drawable.material_heart_fill_icon);
imgHeart.setLayoutParams(new FrameLayout.LayoutParams(50, 50, Gravity.CENTER));
mainFrameLaout.addView(imgHeart);
Add animation on image view
imgHeart.animate()
.scaleXBy(6)
.scaleYBy(6)
.setDuration(700)
.alpha(2)
.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
imgHeart.animate()
.scaleXBy(-6f).scaleYBy(-6f)
.alpha(.1f)
.translationX((heigthAndWidth[0] / 2) - minusWidth)
.translationY(-((heigthAndWidth[1] / 2) - minusHeight))
.setDuration(1000)
.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
// remove image view from framlayout
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
}).start();
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
}).start();
you can use this code :)
private void animeView(View imageView){
Handler handler = new Handler();
final int[] deltaX = {50};
final int[] deltaRotation = {45};
handler.postDelayed(new Runnable() {
#Override
public void run() {
imageView.animate().translationX(deltaX[0])
.rotation(deltaRotation[0]).setDuration(1000) ;
deltaX[0] *=-1 ;
deltaRotation[0] *=-1 ;
handler.postDelayed(this , 1000);
}
},1000);
}