<!--使用默认UI属性--> <com.mcxtzhang.lib.AnimShopButton android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" app:maxCount="3"/> <!--设置了两圆间距--> <com.mcxtzhang.lib.AnimShopButton android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:count="3" app:gapBetweenCircle="90dp" app:maxCount="99"/> <!--仿饿了么--> <com.mcxtzhang.lib.AnimShopButton android:id="@+id/btnEle" android:layout_width="wrap_content" android:layout_height="wrap_content" app:addEnableBgColor="#3190E8" app:addEnableFgColor="#ffffff" app:hintBgColor="#3190E8" app:hintBgRoundValue="15dp" app:hintFgColor="#ffffff" app:maxCount="99"/>
| name | format | description | 中文解释 |
|---|---|---|---|
| isAddFillMode | boolean | Plus button is opened Fill mode default is stroke (false) | 加按钮是否开启fill模式 默认是stroke(false) |
| addEnableBgColor | color | The background color of the plus button | 加按钮的背景色 |
| addEnableFgColor | color | The foreground color of the plus button | 加按钮的前景色 |
| addDisableBgColor | color | The background color when the button is not available | 加按钮不可用时的背景色 |
| addDisableFgColor | color | The foreground color when the button is not available | 加按钮不可用时的前景色 |
| isDelFillMode | boolean | Plus button is opened Fill mode default is stroke (false) | 减按钮是否开启fill模式 默认是stroke(false) |
| delEnableBgColor | color | The background color of the minus button | 减按钮的背景色 |
| delEnableFgColor | color | The foreground color of the minus button | 减按钮的前景色 |
| delDisableBgColor | color | The background color when the button is not available | 减按钮不可用时的背景色 |
| delDisableFgColor | color | The foreground color when the button is not available | 减按钮不可用时的前景色 |
| radius | dimension | The radius of the circle | 圆的半径 |
| circleStrokeWidth | dimension | The width of the circle | 圆圈的宽度 |
| lineWidth | dimension | The width of the line (+ - sign) | 线(+ - 符号)的宽度 |
| gapBetweenCircle | dimension | The spacing between two circles | 两个圆之间的间距 |
| numTextSize | dimension | The textSize of draws the number | 绘制数量的textSize |
| maxCount | integer | max count | 最大数量 |
| count | integer | current count | 当前数量 |
| hintText | string | The hint text when number is 0 | 数量为0时,hint文字 |
| hintBgColor | color | The hint background when number is 0 | 数量为0时,hint背景色 |
| hintFgColor | color | The hint foreground when number is 0 | 数量为0时,hint前景色 |
| hingTextSize | dimension | The hint text size when number is 0 | 数量为0时,hint文字大小 |
| hintBgRoundValue | dimension | The background fillet value when number is 0 | 数量为0时,hint背景圆角值 |
@Override
protected void onDraw(Canvas canvas) {
if (isHintMode) {
//hint 展开
//背景
mHintPaint.setColor(mHintBgColor);
RectF rectF = new RectF(mLeft, mTop
, mWidth - mCircleWidth, mHeight - mCircleWidth);
canvas.drawRoundRect(rectF, mHintBgRoundValue, mHintBgRoundValue, mHintPaint);
//前景文字
mHintPaint.setColor(mHintFgColor);
// 计算Baseline绘制的起点X轴坐标
int baseX = (int) (mWidth / 2 - mHintPaint.measureText(mHintText) / 2);
// 计算Baseline绘制的Y坐标
int baseY = (int) ((mHeight / 2) - ((mHintPaint.descent() + mHintPaint.ascent()) / 2));
canvas.drawText(mHintText, baseX, baseY, mHintPaint);
} else {
//左边
//背景 圆
if (mCount > 0) {
mDelPaint.setColor(mDelEnableBgColor);
} else {
mDelPaint.setColor(mDelDisableBgColor);
}
mDelPaint.setStrokeWidth(mCircleWidth);
mDelPath.reset();
mDelPath.addCircle(mLeft + mRadius, mTop + mRadius, mRadius, Path.Direction.CW);
mDelRegion.setPath(mDelPath, new Region(mLeft, mTop, mWidth - getPaddingRight(), mHeight - getPaddingBottom()));
canvas.drawPath(mDelPath, mDelPaint);
//前景 -
if (mCount > 0) {
mDelPaint.setColor(mDelEnableFgColor);
} else {
mDelPaint.setColor(mDelDisableFgColor);
}
mDelPaint.setStrokeWidth(mLineWidth);
canvas.drawLine(-mRadius / 2, 0,
+mRadius / 2, 0,
mDelPaint);
//数量
//是没有动画的普通写法,x left, y baseLine
canvas.drawText(mCount + "", mLeft + mRadius * 2, mTop + mRadius - (mFontMetrics.top + mFontMetrics.bottom) / 2, mTextPaint);
//右边
//背景 圆
if (mCount < mMaxCount) {
mAddPaint.setColor(mAddEnableBgColor);
} else {
mAddPaint.setColor(mAddDisableBgColor);
}
mAddPaint.setStrokeWidth(mCircleWidth);
float left = mLeft + mRadius * 2 + mGapBetweenCircle;
mAddPath.reset();
mAddPath.addCircle(left + mRadius, mTop + mRadius, mRadius, Path.Direction.CW);
mAddRegion.setPath(mAddPath, new Region(mLeft, mTop, mWidth - getPaddingRight(), mHeight - getPaddingBottom()));
canvas.drawPath(mAddPath, mAddPaint);
//前景 +
if (mCount < mMaxCount) {
mAddPaint.setColor(mAddEnableFgColor);
} else {
mAddPaint.setColor(mAddDisableFgColor);
}
mAddPaint.setStrokeWidth(mLineWidth);
canvas.drawLine(left + mRadius / 2, mTop + mRadius, left + mRadius / 2 + mRadius, mTop + mRadius, mAddPaint);
canvas.drawLine(left + mRadius, mTop + mRadius / 2, left + mRadius, mTop + mRadius / 2 + mRadius, mAddPaint);
}
}
/** * Return true if the region contains the specified point */ public native boolean contains(int x, int y);
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
//hint模式
if (isHintMode) {
onAddClick();
return true;
} else {
if (mAddRegion.contains((int) event.getX(), (int) event.getY())) {
onAddClick();
return true;
} else if (mDelRegion.contains((int) event.getX(), (int) event.getY())) {
onDelClick();
return true;
}
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
return super.onTouchEvent(event);
}
protected void onDelClick() {
if (mCount > 0) {
mCount--;
onCountDelSuccess();
}
}
protected void onAddClick() {
if (mCount < mMaxCount) {
mCount++;
onCountAddSuccess();
} else {
}
}
/**
* 数量增加成功后,使用者回调
*/
public void onCountAddSuccess() {
if (mCount == 1) {
cancelAllAnim();
mAnimReduceHint.start();
} else {
mAnimFraction = 0;
invalidate();
}
}
/**
* 数量减少成功后,使用者回调
*/
public void onCountDelSuccess() {
if (mCount == 0) {
cancelAllAnim();
mAniDel.start();
} else {
mAnimFraction = 0;
invalidate();
}
}
//动画的基准值 动画:减 0~1, 加 1~0 // 普通状态下是0 protected float mAnimFraction; //提示语收缩动画 0-1 展开1-0 //普通模式时,应该是1, 只在 isHintMode true 才有效 protected float mAnimExpandHintFraction;
//背景 mHintPaint.setColor(mHintBgColor); RectF rectF = new RectF(mLeft + (mWidth - mRadius * 2) * mAnimExpandHintFraction, mTop , mWidth - mCircleWidth, mHeight - mCircleWidth); canvas.drawRoundRect(rectF, mHintBgRoundValue, mHintBgRoundValue, mHintPaint);
//动画 mAnimFraction :减 0~1, 加 1~0 , //动画位移Max, float animOffsetMax = (mRadius * 2 +mGapBetweenCircle); //透明度动画的基准 int animAlphaMax = 255; int animRotateMax = 360; //左边 //背景 圆 mDelPaint.setAlpha((int) (animAlphaMax * (1 - mAnimFraction))); mDelPath.reset(); //改变圆心的X坐标,实现位移 mDelPath.addCircle(animOffsetMax * mAnimFraction + mLeft + mRadius, mTop + mRadius, mRadius, Path.Direction.CW); canvas.drawPath(mDelPath, mDelPaint);
//前景 - //旋转动画 canvas.save(); canvas.translate(animOffsetMax * mAnimFraction + mLeft + mRadius, mTop + mRadius); canvas.rotate((int) (animRotateMax * (1 - mAnimFraction))); canvas.drawLine(-mRadius / 2, 0, +mRadius / 2, 0, mDelPaint); canvas.restore();
//数量 canvas.save(); //平移动画 canvas.translate(mAnimFraction * (mGapBetweenCircle / 2 - mTextPaint.measureText(mCount + "") / 2 + mRadius), 0); //旋转动画,旋转中心点,x 是绘图中心,y 是控件中心 canvas.rotate(360 * mAnimFraction, mGapBetweenCircle / 2 + mLeft + mRadius * 2 , mTop + mRadius); //透明度动画 mTextPaint.setAlpha((int) (255 * (1 - mAnimFraction))); //是没有动画的普通写法,x left, y baseLine canvas.drawText(mCount + "", mGapBetweenCircle / 2 - mTextPaint.measureText(mCount + "") / 2 + mLeft + mRadius * 2, mTop + mRadius - (mFontMetrics.top + mFontMetrics.bottom) / 2, mTextPaint); canvas.restore();
//动画 +
mAnimAdd = ValueAnimator.ofFloat(1, 0);
mAnimAdd.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimFraction = (float) animation.getAnimatedValue();
invalidate();
}
});
mAnimAdd.setDuration(350);
//提示语收缩动画 0-1
mAnimReduceHint = ValueAnimator.ofFloat(0, 1);
mAnimReduceHint.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimExpandHintFraction = (float) animation.getAnimatedValue();
invalidate();
}
});
mAnimReduceHint.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mCount == 1) {
//然后底色也不显示了
isHintMode = false;
}
if (mCount == 1) {
Log.d(TAG, "现在还是1 开始收缩动画");
if (mAnimAdd != null && !mAnimAdd.isRunning()) {
mAnimAdd.start();
}
}
}
@Override
public void onAnimationStart(Animator animation) {
if (mCount == 1) {
//先不显示文字了
isShowHintText = false;
}
}
});
mAnimReduceHint.setDuration(350);
//动画 -
mAniDel = ValueAnimator.ofFloat(0, 1);
mAniDel.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimFraction = (float) animation.getAnimatedValue();
invalidate();
}
});
//1-0的动画
mAniDel.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mCount == 0) {
Log.d(TAG, "现在还是0onAnimationEnd() called with: animation = [" + animation + "]");
if (mAnimExpandHint != null && !mAnimExpandHint.isRunning()) {
mAnimExpandHint.start();
}
}
}
});
mAniDel.setDuration(350);
//提示语展开动画
//分析这个动画,最初是个圆。 就是left 不断减小
mAnimExpandHint = ValueAnimator.ofFloat(1, 0);
mAnimExpandHint.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAnimExpandHintFraction = (float) animation.getAnimatedValue();
invalidate();
}
});
mAnimExpandHint.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mCount == 0) {
isShowHintText = true;
}
}
@Override
public void onAnimationStart(Animator animation) {
if (mCount == 0) {
isHintMode = true;
}
}
});
mAnimExpandHint.setDuration(350);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
switch (wMode) {
case MeasureSpec.EXACTLY:
break;
case MeasureSpec.AT_MOST:
//不超过父控件给的范围内,自由发挥
int computeSize = (int) (getPaddingLeft() + mRadius * 2 +mGapBetweenCircle + mRadius * 2 + getPaddingRight() + mCircleWidth * 2);
wSize = computeSize < wSize ? computeSize : wSize;
break;
case MeasureSpec.UNSPECIFIED:
//自由发挥
computeSize = (int) (getPaddingLeft() + mRadius * 2 + mGapBetweenCircle + mRadius * 2 + getPaddingRight() + mCircleWidth * 2);
wSize = computeSize;
break;
}
switch (hMode) {
case MeasureSpec.EXACTLY:
break;
case MeasureSpec.AT_MOST:
int computeSize = (int) (getPaddingTop() + mRadius * 2 + getPaddingBottom() + mCircleWidth * 2);
hSize = computeSize < hSize ? computeSize : hSize;
break;
case MeasureSpec.UNSPECIFIED:
computeSize = (int) (getPaddingTop() + mRadius * 2 + getPaddingBottom() + mCircleWidth * 2);
hSize = computeSize;
break;
}
setMeasuredDimension(wSize, hSize);
//复用时会走这里,所以初始化一些UI显示的参数
mAnimFraction = 0;
initHintSettings();
}
/**
* 根据当前count数量 初始化 hint提示语相关变量
*/
private void initHintSettings() {
if (mCount == 0) {
isHintMode = true;
isShowHintText = true;
mAnimExpandHintFraction = 0;
} else {
isHintMode = false;
isShowHintText = false;
mAnimExpandHintFraction = 1;
}
}
/**
* 设置当前数量
* @param count
* @return
*/
public AnimShopButton setCount(int count) {
mCount = count;
//先暂停所有动画
if (mAnimAdd != null && mAnimAdd.isRunning()) {
mAnimAdd.cancel();
}
if (mAniDel != null && mAniDel.isRunning()) {
mAniDel.cancel();
}
//复用机制的处理
if (mCount == 0) {
// 0 不显示 数字和-号
mAnimFraction = 1;
} else {
mAnimFraction = 0;
}
initHintSettings();
return this;
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有