English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Animation Effect of Adding Goods to Shopping Cart in Android (Bezier Curve)

When writing a mall project, there is usually a shopping cart function. When adding items to the shopping cart, there are some parabolic animations. The specific code is as follows:

The effect is shown as follows:

Thoughts:

  1. Determine the start and end points of the animation
  2. Use quadratic Bézier curve to fill the trajectory between the starting and ending points
  3. Set property animation, ValueAnimator interpolator, and obtain the coordinates of the middle point
  4. Set the x, y coordinates of the control executing the animation to the middle point coordinates obtained above
  5. Enable property animation
  6. Operations when the animation ends

Difficulties:

Usage of PathMeasure
- getLength()
- Understanding the method 'boolean getPosTan(float distance, float[] pos, float[] tan)'

Knowledge points involved:

How to get the absolute coordinates of a control on the screen

//Get the starting point coordinate of the parent layout (used to assist in calculating the start of the animation/The coordinate of the point at the end)
  int[] parentLocation = new int[2];
  rl.getLocationInWindow(parentLocation);

How to use Bezier curve and property animation interpolator ValueAnimator
  

 //    Four, calculate the interpolation coordinates of the intermediate animation (Bezier curve) (which is actually to complete the process from the starting point to the endpoint with the Bezier curve)
    //Start drawing the Bézier curve
    Path path = new Path();
    //Move to the starting point (the starting point of the Bézier curve)
    path.moveTo(startX, startY);
    //Use quadratic Bézier curve: note that the larger the starting coordinate, the greater the horizontal distance of the Bézier curve will be. Generally, the following formula can be used
    path.quadTo((startX + toX) / 2, startY, toX, toY);
    //mPathMeasure is used to calculate the length of the Bezier curve and the coordinates of the intermediate interpolation of the Bezier curve,
    // If it is true, the path will form a closed loop
    mPathMeasure = new PathMeasure(path, false);
    //★★★Attribute animation implementation (interpolation calculation between 0 and the length of the Bezier curve to obtain the distance value of the intermediate process)
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
    valueAnimator.setDuration(1000);
    // Uniform linear interpolation
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        // When the interpolation calculation is going on, get each value in the middle
        // This value is the length of the curve in the middle process (the midpoint coordinates will be obtained based on this value below)
        float value = (Float) animation.getAnimatedValue();
        // ★★★★★Encapsulate the current point coordinates into mCurrentPosition
        // boolean getPosTan(float distance, float[] pos, float[] tan) :
        // Pass a distance distance (0 <= distance <= getLength()), and then calculate the current distance
        // The coordinates of the point and the tangent, pos will automatically fill in the coordinates, this method is very important.
        mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition is the coordinates of the midpoint at this time
        // Set the coordinates of the moving goods image (animation image) to the coordinates of the midpoint
        goods.setTranslationX(mCurrentPosition[0]);
        goods.setTranslationY(mCurrentPosition[1});
      }
    });
//   Five, start executing the animation
    valueAnimator.start();

All code:

package cn.c.com.beziercurveanimater;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
  private RecyclerView mRecyclerView;
  private ImageView cart;
  private ArrayList<Bitmap> bitmapList = new ArrayList<>();
  private RelativeLayout rl;
  private PathMeasure mPathMeasure;
  /**
   * The coordinates of the points in the middle process of the Bezier curve
   */
  private float[] mCurrentPosition = new float[2];
  private TextView count;
  private int i = 0;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();
    initImg();
    MyAdapter myAdapter = new MyAdapter(bitmapList);
    mRecyclerView.setAdapter(myAdapter);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
  }
  private void initImg() {
    bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin));
    bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin1));
    bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin91));
  }
  private void initView() {
    mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    cart = (ImageView) findViewById(R.id.cart);
    rl = (RelativeLayout) findViewById(R.id.rl);
    count = (TextView) findViewById(R.id.count);
  }
  class MyAdapter extends RecyclerView.Adapter<MyVH> {
    private ArrayList<Bitmap> bitmapList;
    public MyAdapter(ArrayList<Bitmap> bitmapList) {
      this.bitmapList = bitmapList;
    }
    @Override
    public MyVH onCreateViewHolder(ViewGroup parent, int viewType) {
      LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
      View itemView = inflater.inflate(R.layout.item, parent, false);
      MyVH myVH = new MyVH(itemView);
      return myVH;
    }
    @Override
    public void onBindViewHolder(final MyVH holder, final int position) {
      holder.iv.setImageBitmap(bitmapList.get(position));
      holder.buy.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          addCart(holder.iv);
        }
      });
    }
    @Override
    public int getItemCount() {
      return bitmapList.size();
    }
  }
  /**
   * ★★★★★ Add the product to the shopping cart animation effect ★★★★★
   * @param iv
   */
  private void addCart(ImageView iv) {
//   1. Create the main theme for the animation---ImageView
    //Code creates a new ImageView with the image resource being the same as the image in the above ImageView
    // This image is the one used for the animation, starting from the initial position, moving along a parabolic (Bezier curve) path, and finally into the shopping cart)
    final ImageView goods = new ImageView(MainActivity.this);
    goods.setImageDrawable(iv.getDrawable());
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
    rl.addView(goods, params);
//    Two, calculate the animation start/Preparation for the coordinate of the end point
    //Get the starting point coordinate of the parent layout (used to assist in calculating the start of the animation/The coordinate of the point at the end)
    int[] parentLocation = new int[2];
    rl.getLocationInWindow(parentLocation);
    //Get the coordinate of the product image (used to calculate the starting coordinate of the animation)
    int startLoc[] = new int[2];
    iv.getLocationInWindow(startLoc);
    //Get the coordinate of the shopping cart image (used to calculate the coordinate after the animation ends)
    int endLoc[] = new int[2];
    cart.getLocationInWindow(endLoc);
//    Three, start calculating the animation start/The ending coordinate
    //The starting point of the falling product: the starting point of the product-Parent layout starting point+Half of the product image
    float startX = startLoc[0] - parentLocation[0] + iv.getWidth() / 2;
    float startY = startLoc[1] - parentLocation[1] + iv.getHeight() / 2;
    //The final coordinate of the product after falling: the starting point of the shopping cart-Parent layout starting point+The image of the shopping cart1/5
    float toX = endLoc[0] - parentLocation[0] + cart.getWidth() / 5;
    float toY = endLoc[1] - parentLocation[1];
//    Four, calculate the interpolation coordinates of the intermediate animation (Bezier curve) (which is actually to complete the process from the starting point to the endpoint with the Bezier curve)
    //Start drawing the Bézier curve
    Path path = new Path();
    //Move to the starting point (the starting point of the Bézier curve)
    path.moveTo(startX, startY);
    //Use quadratic Bézier curve: note that the larger the starting coordinate, the greater the horizontal distance of the Bézier curve will be. Generally, the following formula can be used
    path.quadTo((startX + toX) / 2, startY, toX, toY);
    //mPathMeasure is used to calculate the length of the Bezier curve and the coordinates of the intermediate interpolation of the Bezier curve,
    // If it is true, the path will form a closed loop
    mPathMeasure = new PathMeasure(path, false);
    //★★★Attribute animation implementation (interpolation calculation between 0 and the length of the Bezier curve to obtain the distance value of the intermediate process)
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
    valueAnimator.setDuration(1000);
    // Uniform linear interpolation
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        // When the interpolation calculation is going on, get each value in the middle
        // This value is the length of the curve in the middle process (the midpoint coordinates will be obtained based on this value below)
        float value = (Float) animation.getAnimatedValue();
        // ★★★★★Encapsulate the current point coordinates into mCurrentPosition
        // boolean getPosTan(float distance, float[] pos, float[] tan) :
        // Pass a distance distance (0 <= distance <= getLength()), and then calculate the current distance
        // The coordinates of the point and the tangent, pos will automatically fill in the coordinates, this method is very important.
        mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition is the coordinates of the midpoint at this time
        // Set the coordinates of the moving goods image (animation image) to the coordinates of the midpoint
        goods.setTranslationX(mCurrentPosition[0]);
        goods.setTranslationY(mCurrentPosition[1});
      }
    });
//   Five, start executing the animation
    valueAnimator.start();
//   Six, handling after animation ends
    valueAnimator.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animation) {
      }
      //After the animation ends:
      @Override
      public void onAnimationEnd(Animator animation) {
        // Add the number of items in the shopping cart1
        i++;
        count.setText(String.valueOf(i));
        // Remove the moving imageview from the parent layout
        rl.removeView(goods);
      }
      @Override
      public void onAnimationCancel(Animator animation) {
      }
      @Override
      public void onAnimationRepeat(Animator animation) {
      }
    });
  }
  class MyVH extends RecyclerView.ViewHolder {
    private ImageView iv;
    private TextView buy;
    public MyVH(View itemView) {
      super(itemView);
      iv = (ImageView) itemView.findViewById(R.id.iv);
      buy = (TextView) itemView.findViewById(R.id.buy);
    }
  }
}

That's all for this article. Hope it helps everyone's learning and also hope everyone supports the Naiya Tutorial.

Statement: The content of this article is from the Internet, the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been edited by humans, and does not assume relevant legal liabilities. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please report by email to codebox.com (replace # with @ when sending an email) and provide relevant evidence. Once verified, this site will immediately delete the infringing content.

You May Also Like