android 未读消息气泡,Android未读消息拖动气泡示例

文章目录

前言

最终效果图及思路

关键代码

1.定义,初始化等

2.onDraw中绘制包括三样绘制

3.onTouchEvent中

4.反弹和爆炸动画

总结

前言

拖动清除未读消息可以说在很多应用中都很常见,也被用户广泛接受。本文是一个可以供参考的Demo,希望能有帮助。

提示:以下是本篇文章正文内容,下面案例可供参考

最终效果图及思路

83321eb18dd9da70984ac916d36f5c87.png

0c0a4ef007ba0d31ee93016888eabf3b.png

实现关键:气泡中间的两条边,分别是以ab,cd为数据点,G为控制点的贝塞尔曲线。

步骤:绘制圆背景以及文本;连接情况绘制贝塞尔曲线;另外端点绘制一个圆

关键代码

1.定义,初始化等

状态:静止、连接、分离、消失

在onSizeChanged中初始化状态,固定气泡以及可动气泡的圆心

代码如下(示例):

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

init(w, h);

}

private void init(int w, int h) {

mBubbleState = BUBBLE_STATE_DEFAULT;

//设置固定气泡圆心初始坐标

if (mBubFixedCenter == null) {

mBubFixedCenter = new PointF(w / 2, h / 2);

} else {

mBubFixedCenter.set(w / 2, h / 2);

}

//设置可动气泡圆心初始坐标

if (mBubMovableCenter == null) {

mBubMovableCenter = new PointF(w / 2, h / 2);

} else {

mBubMovableCenter.set(w / 2, h / 2);

}

}

2.onDraw中绘制包括三样绘制

第一样:静止,连接,分离状态都需要绘制圆背景以及文本:

//静止,连接,分离状态都需要绘制圆背景以及文本

if (mBubbleState != BUBBLE_STATE_DISMISS) {

canvas.drawCircle(mBubMovableCenter.x, mBubMovableCenter.y, mBubMovableRadius, mBubblePaint);

mTextPaint.getTextBounds(mTextStr, 0, mTextStr.length(), mTextRect);

canvas.drawText(mTextStr, mBubMovableCenter.x - mTextRect.width() / 2, mBubMovableCenter.y + mTextRect.height() / 2, mTextPaint);

}

第二样:连接状态绘制贝塞尔曲线①。

if (mBubbleState == BUBBLE_STATE_CONNECT) {

//绘制静止的气泡

canvas.drawCircle(mBubFixedCenter.x, mBubFixedCenter.y, mBubFixedRadius, mBubblePaint);

//计算控制点的坐标

int iAnchorX = (int) ((mBubMovableCenter.x + mBubFixedCenter.x) / 2);

int iAnchorY = (int) ((mBubMovableCenter.y + mBubFixedCenter.y) / 2);

float sinTheta = (mBubMovableCenter.y - mBubFixedCenter.y) / mDist;

float cosTheta = (mBubMovableCenter.x - mBubFixedCenter.x) / mDist;

//D

float iBubFixedStartX = mBubFixedCenter.x - mBubFixedRadius * sinTheta;

float iBubFixedStartY = mBubFixedCenter.y + mBubFixedRadius * cosTheta;

//C

float iBubMovableEndX = mBubMovableCenter.x - mBubMovableRadius * sinTheta;

float iBubMovableEndY = mBubMovableCenter.y + mBubMovableRadius * cosTheta;

//A

float iBubFixedEndX = mBubFixedCenter.x + mBubFixedRadius * sinTheta;

float iBubFixedEndY = mBubFixedCenter.y - mBubFixedRadius * cosTheta;

//B

float iBubMovableStartX = mBubMovableCenter.x + mBubMovableRadius * sinTheta;

float iBubMovableStartY = mBubMovableCenter.y - mBubMovableRadius * cosTheta;

mBezierPath.reset();

mBezierPath.moveTo(iBubFixedStartX, iBubFixedStartY);

mBezierPath.quadTo(iAnchorX, iAnchorY, iBubMovableEndX, iBubMovableEndY);

mBezierPath.lineTo(iBubMovableStartX, iBubMovableStartY);

mBezierPath.quadTo(iAnchorX, iAnchorY, iBubFixedEndX, iBubFixedEndY);

mBezierPath.close();

canvas.drawPath(mBezierPath, mBubblePaint);

}

第三样:消失状态执行爆炸动画

// 认为是消失状态,执行爆炸动画

if (mBubbleState == BUBBLE_STATE_DISMISS && mCurDrawableIndex < mBurstBitmapsArray.length) {

mBurstRect.set(

(int) (mBubMovableCenter.x - mBubMovableRadius),

(int) (mBubMovableCenter.y - mBubMovableRadius),

(int) (mBubMovableCenter.x + mBubMovableRadius),

(int) (mBubMovableCenter.y + mBubMovableRadius));

canvas.drawBitmap(mBurstBitmapsArray[mCurDrawableIndex], null, mBurstRect, mBubblePaint);

}

3.onTouchEvent中

按下:区分静止状态和连接状态

case MotionEvent.ACTION_DOWN:

if (mBubbleState != BUBBLE_STATE_DISMISS) {

mDist = (float) Math.hypot(event.getX() - mBubFixedCenter.x, event.getY() - mBubFixedCenter.y);

if (mDist < mBubbleRadius + MOVE_OFFSET) {

//加上MOVE_OFFSET是为了方便拖拽

mBubbleState = BUBBLE_STATE_CONNECT;

} else {

mBubbleState = BUBBLE_STATE_DEFAULT;

}

}

break;

移动:判断是否到了分离状态

case MotionEvent.ACTION_MOVE:

if (mBubbleState != BUBBLE_STATE_DEFAULT) {

mDist = (float) Math.hypot(event.getX() - mBubFixedCenter.x, event.getY() - mBubFixedCenter.y);

mBubMovableCenter.x = event.getX();

mBubMovableCenter.y = event.getY();

if (mBubbleState == BUBBLE_STATE_CONNECT) {

if (mDist < mMaxDist - MOVE_OFFSET) {

mBubFixedRadius = mBubbleRadius - mDist / 8;

} else {

mBubbleState = BUBBLE_STATE_APART;

}

}

invalidate();

}

break;

弹起:判断是否已经到了分离状态,分离状态爆炸,未分离反弹

case MotionEvent.ACTION_UP:

if (mBubbleState == BUBBLE_STATE_CONNECT) {

// 橡皮筋动画

startBubbleRestAnim();

} else if (mBubbleState == BUBBLE_STATE_APART) {

if (mDist < 2 * mBubbleRadius){

//反弹动画

startBubbleRestAnim();

}else{

// 爆炸动画

startBubbleBurstAnim();

}

}

break;

4.反弹和爆炸动画

/**

* 连接状态下松开手指,执行类似橡皮筋动画

*/

private void startBubbleRestAnim() {

ValueAnimator anim = ValueAnimator.ofObject(new PointFEvaluator(),

new PointF(mBubMovableCenter.x, mBubMovableCenter.y),

new PointF(mBubFixedCenter.x, mBubFixedCenter.y));

anim.setDuration(200);

anim.setInterpolator(new OvershootInterpolator(5f));

anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mBubMovableCenter = (PointF) animation.getAnimatedValue();

invalidate();

}

});

anim.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

mBubbleState = BUBBLE_STATE_DEFAULT;

}

});

anim.start();

}

/**

* 爆炸动画

*/

private void startBubbleBurstAnim() {

//将气泡改成消失状态

mBubbleState = BUBBLE_STATE_DISMISS;

ValueAnimator animator = ValueAnimator.ofInt(0, mBurstBitmapsArray.length);

animator.setInterpolator(new LinearInterpolator());

animator.setDuration(500);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mCurDrawableIndex = (int) animation.getAnimatedValue();

invalidate();

}

});

animator.start();

}

总结

注:①贝塞尔曲线参考博文

本文完,有需要参考的同学→文中Demo下载地址

本系列文章引导页点击这里

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值