Do you mean somthing like this?

Here is How I do it
view_card.xml
Just a typical layout there is no important code here
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="#E6EFF1"
app:cardCornerRadius="12dp"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:text="Add To Cart"
android:textSize="11sp"
app:layout_constraintBottom_toBottomOf="@+id/imageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="1.0" />
<ImageView
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:src="@drawable/a2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AIMAN"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/button"
app:layout_constraintTop_toTopOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
activity_main.xml
Just a typical layout there is no important code here
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:id="@+id/card"
android:layout_width="130dp"
android:layout_height="100dp"
android:layout_marginTop="@dimen/cardMargin"
app:cardBackgroundColor="#EDEAF1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.943"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:src="@drawable/ic_cart" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:clipToPadding="false"
android:orientation="horizontal"
android:padding="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/card"
tools:listitem="@layout/view_card" />
</androidx.constraintlayout.widget.ConstraintLayout>
CustomAdapter.java
Focus here on the remove(..) function, here when you notify by the function notifyItemRemoved(position) the animation after the card removes going to be applied, you don't need to do anything else.
List<Drawable> list;
CustomViewListener listener;
public CustomAdapter() {
list = new ArrayList<>();
}
public void setListener(CustomViewListener listener) {
this.listener = listener;
}
public void add(Drawable drawable) {
list.add(drawable);
notifyDataSetChanged();
}
@NonNull
@Override
public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_card, parent, false);
return new CustomViewHolder(inflate, listener);
}
@Override
public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
holder.bind(list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
public void remove(Drawable drawable) {
int position = list.indexOf(drawable);
list.remove(drawable);
notifyItemRemoved(position);
}
public interface CustomViewListener {
void onFly(View view, Drawable drawable, int x, int y, int width, int hight);
}
}
CustomViewHolder.java
Foucse here at the following
initSize() to get the CardView size witch we need later to pass it for the temporary ImageView in the MainActivity
- at the
binding.button.setOnClickListener we going to get the CardView location and after that we call the function onFly to pass the information we need to the MainActivity
class CustomViewHolder extends RecyclerView.ViewHolder {
int width = 0, height = 0;
Drawable drawable;
CustomAdapter.CustomViewListener listener;
ViewCardBinding binding;
public CustomViewHolder(@NonNull View itemView, CustomAdapter.CustomViewListener listener) {
super(itemView);
binding = ViewCardBinding.bind(itemView);
this.listener = listener;
initSize();
initEvent();
}
private void initSize() {
ViewTreeObserver treeObserver = binding.card.getViewTreeObserver();
treeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
binding.card.getViewTreeObserver().removeOnGlobalLayoutListener(this);
width = binding.card.getMeasuredWidth();
height = binding.card.getMeasuredHeight();
}
});
}
public void bind(Drawable drawable) {
this.drawable = drawable;
binding.imageView.setImageDrawable(drawable);
binding.card.setVisibility(View.VISIBLE);
}
private void initEvent() {
binding.button.setOnClickListener(view -> {
int[] location = new int[2];
binding.card.getLocationInWindow(location);
int x = location[0];
int y = location[1];
listener.onFly(binding.card, drawable, x, y, width, height);
binding.card.setVisibility(View.INVISIBLE);
});
}
}
MainActivity.java
Foucse here at the following
Inside the function handleAnimateTheCard(..)
1- getTemporaryImageView(..) create temporary ImageView with the width and hight of CardView from the RecyclerView
2- loadBitmapFromView(..) draw inside a BitMap to look like the CardView of the RecyclerView
Inside the function startAnime(..) going to create animations you request by the coordinates of the CardView inside the RecyclerView ,and the RelativeLayout inside the MainActivty, here we have three animation pop up then moving the card with fading
after the second animation finish going to remove the card from the RecyclerView
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
CustomAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
adapter = new CustomAdapter();
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true);
binding.recyclerView.setLayoutManager(layoutManager);
binding.recyclerView.setAdapter(adapter);
adapter.setListener(this::handleAnimateTheCard);
addSomeData();
}
void handleAnimateTheCard(View view, Drawable drawable, int x, int y, int width, int hight) {
ImageView tempImage = getTemporaryImageView(width, hight);
Bitmap viewBitmap = loadBitmapFromView(view);
tempImage.setImageBitmap(viewBitmap);
// here because the y value not include the toolbar and actionbar hight
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int topOffset = dm.heightPixels - binding.getRoot().getMeasuredHeight();
y -= topOffset;
int[] location = new int[2];
binding.card.getLocationInWindow(location);
int cartX = location[0] - 100;
int cartY = location[1] - topOffset;
tempImage.setAlpha(1f);
startAnime(tempImage, drawable, x, y, cartX, cartY);
}
private ImageView getTemporaryImageView(int width, int hight) {
ImageView tempImage = new ImageView(MainActivity.this);
binding.getRoot().addView(tempImage);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(width, hight);
tempImage.setLayoutParams(params);
return tempImage;
}
private void startAnime(ImageView tempImage, Drawable drawable, int x, int y, int cartX, int cartY) {
ObjectAnimator popAnime = ObjectAnimator.ofFloat(tempImage, "translationX", x, x);
ObjectAnimator popAnime2 = ObjectAnimator.ofFloat(tempImage, "translationY", y, y);
ObjectAnimator popAnime3 = ObjectAnimator.ofFloat(tempImage, "scaleY", 1f, 0.9f, 1.2f);
ObjectAnimator popAnime4 = ObjectAnimator.ofFloat(tempImage, "scaleX", 1f, 0.9f, 1.2f);
AnimatorSet popAnimeSet = new AnimatorSet();
popAnimeSet.setDuration(200).playTogether(popAnime, popAnime2, popAnime3, popAnime4);
ObjectAnimator moveAnime = ObjectAnimator.ofFloat(tempImage, "translationX", x, cartX);
ObjectAnimator moveAnime2 = ObjectAnimator.ofFloat(tempImage, "translationY", y, cartY);
ObjectAnimator moveAnime3 = ObjectAnimator.ofFloat(tempImage, "scaleY", 1.2f, 0.5f);
ObjectAnimator moveAnime4 = ObjectAnimator.ofFloat(tempImage, "scaleX", 1.2f, 0.5f);
AnimatorSet moveAnimeSet = new AnimatorSet();
moveAnimeSet.setDuration(500).playTogether(moveAnime, moveAnime2, moveAnime3, moveAnime4);
moveAnimeSet.setStartDelay(50);
moveAnimeSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
tempImage.animate().alpha(0f).setDuration(600);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(popAnimeSet, moveAnimeSet);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
adapter.remove(drawable);
}
});
animatorSet.start();
}
public Bitmap loadBitmapFromView(View view) {
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
view.draw(canvas);
return returnedBitmap;
}
private void addSomeData() {
adapter.add(ContextCompat.getDrawable(this, R.drawable.a1));
adapter.add(ContextCompat.getDrawable(this, R.drawable.a2));
adapter.add(ContextCompat.getDrawable(this, R.drawable.a3));
}
}