安卓自定义view仿小米商城购物车动画
程序员文章站
2022-04-25 09:10:20
...
通过自定义View与ViewGroup实现小米商城购物车效果
用到的知识点
- 自定义View
- 自定义ViewGroup
- 贝塞尔曲线
原理
- 通过贝塞尔曲线实现商品抛入购物车的路径
- 自定义ViewGroup实现添加多个商品进购物车的动画
- 自定义View绘制心以及购物车图案
代码
一.绘制底部背景View
1.通过Path绘制第一部分,绘制心以及文字
通过贝赛尔曲线绘制心形
/**
* 绘制喜欢
*
* @param canvas
* @param x
* @param y
*/
private void drawLove(Canvas canvas, float x, float y) {
canvas.save();
canvas.translate(x, y);
Path leftPath = new Path();
leftPath.moveTo(0, -40);
Path rightPath = new Path();
rightPath.moveTo(0, -40);
leftPath.cubicTo(0, -40, -30, -80, -35, -40);
leftPath.cubicTo(-35, -40, -30, -30, 0, 10);
rightPath.cubicTo(0, -40, 30, -80, 35, -40);
rightPath.cubicTo(35, -40, 30, -30, 0, 10);
if (isLove) {
mLovePaint.setStyle(Paint.Style.FILL);
mLovePaint.setColor(Color.RED);
} else {
mLovePaint.setStyle(Paint.Style.STROKE);
mLovePaint.setColor(Color.BLACK);
}
mLovePaint.setStrokeWidth(3);
canvas.drawPath(leftPath, mLovePaint);
canvas.drawPath(rightPath, mLovePaint);
canvas.restore();
float measureText = mTextPaint.measureText("喜欢", 0, "喜欢".length());
canvas.drawText("喜欢", x - measureText / 2, y + 50, mTextPaint);
}
2.绘制购物车区域 绘制购物车图形以及文购物车文字
通过Path的拼接绘制购物车图形
/**
* 绘制购物车
*
* @param canvas
* @param x
* @param y
*/
private void drawShoppingCart(Canvas canvas, float x, float y) {
canvas.save();
canvas.translate(x, y);
Path mPath = new Path();
mPath.moveTo(-40, -60);
mPath.lineTo(-30, -60);
mPath.lineTo(-20, 0);
mPath.lineTo(20, 0);
mPath.lineTo(30, -40);
mPath.lineTo(-10, -40);
Path mPath2 = new Path();
mPath2.moveTo(-10, -25);
mPath2.lineTo(10, -25);
mShoppingCartPaint.setStyle(Paint.Style.STROKE);
mShoppingCartPaint.setStrokeWidth(5);
mShoppingCartPaint.setColor(Color.BLACK);
canvas.drawPath(mPath, mShoppingCartPaint);
canvas.drawPath(mPath2, mShoppingCartPaint);
mShoppingCartPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(-15, 10, 5, mShoppingCartPaint);
canvas.drawCircle(15, 10, 5, mShoppingCartPaint);
mShoppingCartPaint.setColor(Color.RED);
canvas.drawCircle(30, -40, 20, mShoppingCartPaint);
String strNum = mProductTotal + "";
mTextPaint.setTextSize(20);
mTextPaint.setColor(Color.WHITE);
float strNumLength = mTextPaint.measureText(strNum, 0, strNum.length());
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
canvas.drawText(strNum, 30 - strNumLength / 2, -40 - (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.top, mTextPaint);
canvas.restore();
String str = "购物车";
mTextPaint.setTextSize(30);
mTextPaint.setColor(Color.BLACK);
float measureText = mTextPaint.measureText(str, 0, str.length());
canvas.drawText(str, x - measureText / 2, y + 50, mTextPaint);
}
3.绘制加入购物车文字
通过FontMetrics实现文字在矩形中心居中对齐
/**
* 绘制加入购物车购物车
*
* @param canvas
* @param x
* @param y
*/
private void drawShoppingText(Canvas canvas, float x, float y) {
String str = "加入购物车";
TextPaint textPaint = new TextPaint();
textPaint.setTextSize(50);
float measureText = textPaint.measureText(str, 0, str.length());
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float v = fontMetrics.bottom - fontMetrics.top;
canvas.drawText(str, x - measureText / 2, y - v / 2 - fontMetrics.top, textPaint);
}
二.绘制动画View
1.绘制商品图片在抛物线路径上,抛物线路径由贝塞尔曲线组成,通过不断的改变数值实现商品图片抛物线移动
/**
* 绘制商品图片在抛物线路径上
* @param canvas
*/
private void drawProductOnPath(Canvas canvas) {
PointF mCurveStart = new PointF();//曲线开始的点
PointF mCurveMiddle = new PointF();//曲线中间点
PointF mCurveEnd = new PointF();//曲线结束的点
mCurveStart.set(measuredWidth * 0.7f, measuredHeight - 85);
mCurveMiddle.set(measuredWidth * 0.4f, 0);
mCurveEnd.set(measuredWidth * 0.3f, measuredHeight - 85);
Path mCurvePath = new Path();//移动曲线
mCurvePath.moveTo(mCurveStart.x, mCurveStart.y);
mCurvePath.cubicTo(mCurveStart.x, mCurveStart.y, mCurveMiddle.x, mCurveMiddle.y, mCurveEnd.x, mCurveEnd.y);
PathMeasure pathMeasure = new PathMeasure();
pathMeasure.setPath(mCurvePath, false);
float[] pos = new float[2];
pathMeasure.getPosTan(pathMeasure.getLength() * percent, pos, null);
Matrix matrix = new Matrix();
matrix.postTranslate(pos[0] - newBitmap.getWidth() / 2, pos[1] - newBitmap.getHeight() / 2);
canvas.drawBitmap(newBitmap, matrix, mBitmapPaint);
}
2.ValueAnimator 数值改变的同时从绘View,实现商品图片的抛入购物车的动画效果,当View添加的时候start此ValueAnimator
/**
* 改变数值实现动画
*/
private void initAnimator() {
valueAnimator = ValueAnimator.ofInt(ints);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
percent = animatedValue / 100f;
if (percent < 0.8) {
int height = (int) (bitmapWidth * (1 - percent));
int width = (int) (bitmapHeight * (1 - percent));
if (width > 0 && height > 0) {
newBitmap = scaleBitmap(bitmap, 1 - percent);
}
}
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mBitmapPaint.setAlpha(0);
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mBitmapPaint.setAlpha(255);
}
});
valueAnimator.setDuration(500);
valueAnimator.setInterpolator(new AccelerateInterpolator());
}
自定义ViewGroup实现购物车效果
1.ViewGroup初始化的时候将底部背景View添加进ViewGroup并且Layout的在底部
2.当点击加入购物车时候,将动画View添加进此ViewGroup,并且启动动画绘制界面实现商品抛进购物车效果。
@Override
public void add(int mProductTotal) {
if (shoppingCartListener != null) {
shoppingCartListener.add(mProductTotal);
}
ShoppingAnimChildView shoppingAnimView = new ShoppingAnimChildView(getContext());
if (mProductBitmap != null) {
shoppingAnimView.setProductBitmap(mProductBitmap);
}
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
addView(shoppingAnimView, layoutParams);
requestLayout();
shoppingAnimView.startAnim();
}
详细代码见Github传送门
欢迎大家star,fork
有很多不足,望见谅
可以直接下载代码使用
使用方法如下
使用方法
1.布局文件添加以下属性
<com.yhongm.shoppingcart.ShoppingCartView
android:id="@+id/vg"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="300dp" />
2.java方法:
scvg.setProductBitmap(产品图片bitmap); 设置产品图片
scvg.setShoppingCartListener(this); 设置点击监听