A, introducing
- 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.
- The layout mainly uses CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+TabLayout+ViewPager
- Animation mainly uses second-order Bezier curve and attribute animation
- The messaging uses the EventBus common event
Second, the general idea
-
As shown in the figure, there are three main points, starting point, ending point, and control point of Bezier curve
-
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
-
The destination is the position of the shopping cart basket, similar to the starting point
mShoppingCart.getLocationInWindow(endPosition); Copy the code
-
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
-
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
-
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
-
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
-
View position argument
-
Bezier curve of Path