A, introducing

  1. In fact, I always thought that the animation of adding goods to shopping cart like ele. me or Meituan takeout would be difficult, but it is not as difficult as I thought.
  2. The layout mainly uses CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+TabLayout+ViewPager
  3. Animation mainly uses second-order Bezier curve and attribute animation
  4. The messaging uses the EventBus common event

Second, the general idea

  1. As shown in the figure, there are three main points, starting point, ending point, and control point of Bezier curve

  2. The starting point is the position of the View to be clicked, which can generally be obtained as follows. StartPosition [0] is the start coordinate of x axis, startPosition[1] is the end coordinate of Y axis, two points can be regarded as the two endpoints above the diagonal (x coordinate of upper left corner, Y coordinate of lower right corner)

    // Start bezier data point
    int[] startPosition = new int[2];
    view.getLocationOnScreen(startPosition);
    Copy the code
  3. The destination is the position of the shopping cart basket, similar to the starting point

    mShoppingCart.getLocationInWindow(endPosition);
    Copy the code
  4. The control point, the control point I chose is C in the figure above, which is the y coordinate of A and the X coordinate of B

    controlPosition[0] = endPosition[0];
    controlPosition[1] = startPosition[1];
    Copy the code
  5. What needs to be noted is that I am not sure whether it is because of my layout problem, the point A that I click always has an offset. Later, after my colleague reminded me, I subtracted the Y-axis coordinate of TabLayout, namely the position.

    / / starting point
    int[] startPosition;
    / / the end
    int[] endPosition = new int[2];
    // Bezier control point
    int[] controlPosition = new int[2];
    / / tablayout position
    int[] tablayoutPosition = new int[2];
    
    startPosition = data.getStartPosition();
    mShoppingCart.getLocationInWindow(endPosition);
    mTabLayout.getLocationInWindow(tablayoutPosition);
    // Handle the y offset of the starting point
    startPosition[1] = startPosition[1] - tablayoutPosition[1] - mTabLayout.getHeight();
    // The endpoint is centered
    endPosition[0] = endPosition[0] + (mShoppingCart.getWidth() / 2);
    controlPosition[0] = endPosition[0];
    controlPosition[1] = startPosition[1];
    Copy the code
  6. Draw bezier curves using Path’s quadTo method, using PathMeasure to get coordinates of points (with valueanimator.offloat () and getPosTan() to get coordinates)

    Path path = new Path();
    path.moveTo(startPosition[0], startPosition[1]);
    path.quadTo(controlPosition[0], controlPosition[1], endPosition[0], endPosition[1]);
    PathMeasure pathMeasure = new PathMeasure();
    // false indicates that path is not closed
    pathMeasure.setPath(path, false);
    
    // ofFloat is a generator
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, pathMeasure.getLength());
    // Constant linear interpolator
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.setDuration(800);
    valueAnimator.addUpdateListener(animation -> {
        float value = (Float) animation.getAnimatedValue();
        pathMeasure.getPosTan(value, currentPosition, null);
        imageView.setX(currentPosition[0]);
        imageView.setY(currentPosition[1]);
    });
    valueAnimator.start();
    Copy the code
  7. Here is a zooming in and out animation of the shopping cart basket using the properties animation

    / / mShoppingCart is the View
    ObjectAnimator shoppingCartX = ObjectAnimator.ofFloat(mShoppingCart, "scaleX".1.0 f.1.3 f.1.0 f);
    ObjectAnimator shoppingCartY = ObjectAnimator.ofFloat(mShoppingCart, "scaleY".1.0 f.1.3 f.1.0 f);
    shoppingCartX.setInterpolator(new AccelerateInterpolator());
    shoppingCartY.setInterpolator(new AccelerateInterpolator());
    AnimatorSet shoppingCart = new AnimatorSet();
    shoppingCart
            .play(shoppingCartX)
            .with(shoppingCartY);
    shoppingCart.setDuration(800);
    shoppingCart.start();
    Copy the code

Third, a slightly complete majority of the code

private void AddAnimation(AddEventBean data) {
    / / starting point
    int[] startPosition;
    / / the end
    int[] endPosition = new int[2];
    // Bezier control point
    int[] controlPosition = new int[2];
    // The current position
    float[] currentPosition = new float[2];
    / / tablayout position
    int[] tablayoutPosition = new int[2];

    startPosition = data.getStartPosition();
    mShoppingCart.getLocationInWindow(endPosition);
    mTabLayout.getLocationInWindow(tablayoutPosition);
    // Handle the y offset of the starting point
    startPosition[1] = startPosition[1] - tablayoutPosition[1] - mTabLayout.getHeight();
    // The endpoint is centered
    endPosition[0] = endPosition[0] + (mShoppingCart.getWidth() / 2);
    controlPosition[0] = endPosition[0];
    controlPosition[1] = startPosition[1];


    final ImageView imageView = new ImageView(this);
    mConView.addView(imageView);
    imageView.setImageResource(R.drawable.specialadd);
    imageView.getLayoutParams().width = getResources().getDimensionPixelSize(R.dimen.dp_px_30);
    imageView.getLayoutParams().height = getResources().getDimensionPixelSize(R.dimen.dp_px_30);
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setVisibility(View.VISIBLE);
    imageView.setX(startPosition[0]);
    imageView.setY(startPosition[1]);

    Path path = new Path();
    path.moveTo(startPosition[0], startPosition[1]);
    path.quadTo(controlPosition[0], controlPosition[1], endPosition[0], endPosition[1]);
    PathMeasure pathMeasure = new PathMeasure();
    // false indicates that path is not closed
    pathMeasure.setPath(path, false);

    // ofFloat is a generator
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, pathMeasure.getLength());
    // Constant linear interpolator
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.setDuration(800);
    valueAnimator.addUpdateListener(animation -> {
        float value = (Float) animation.getAnimatedValue();
        pathMeasure.getPosTan(value, currentPosition, null);
        imageView.setX(currentPosition[0]);
        imageView.setY(currentPosition[1]);
    });
    valueAnimator.start();

    ObjectAnimator shoppingCartX = ObjectAnimator.ofFloat(mShoppingCart, "scaleX".1.0 f.1.3 f.1.0 f);
    ObjectAnimator shoppingCartY = ObjectAnimator.ofFloat(mShoppingCart, "scaleY".1.0 f.1.3 f.1.0 f);
    shoppingCartX.setInterpolator(new AccelerateInterpolator());
    shoppingCartY.setInterpolator(new AccelerateInterpolator());
    AnimatorSet shoppingCart = new AnimatorSet();
    shoppingCart
            .play(shoppingCartX)
            .with(shoppingCartY);
    shoppingCart.setDuration(800);
    shoppingCart.start();

    valueAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {}// When the animation ends:
        @Override
        public void onAnimationEnd(Animator animation) {
            goodsChange(data);
        }

        @Override
        public void onAnimationCancel(Animator animation) {}@Override
        public void onAnimationRepeat(Animator animation) {}}); }Copy the code

Four, roughly write down the layout (also counted as a backup)

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    . .>

    <RelativeLayout
        . .>Top resident toolbar</RelativeLayout>

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <android.support.design.widget.AppBarLayout
            . .>

            <android.support.design.widget.CollapsingToolbarLayout
                . .
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <LinearLayout
                    . .>View above TabLayout</LinearLayout>

            </android.support.design.widget.CollapsingToolbarLayout>

            <android.support.design.widget.TabLayout
                . . />

        </android.support.design.widget.AppBarLayout>

        <RelativeLayout
            . .
            android:fillViewport="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <android.support.v4.view.ViewPager
                android:id="@+id/view_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </RelativeLayout>

    </android.support.design.widget.CoordinatorLayout>

    <LinearLayout
        . .>Bottom of the shopping cart</LinearLayout>
</LinearLayout>
Copy the code

5. Recommended resources

  1. View position argument

  2. Bezier curve of Path