欢迎来到代码驿站!

Android代码

当前位置:首页 > 移动开发 > Android代码

Android未读消息拖动气泡示例代码详解(附源码)

时间:2021-07-14 07:56:39|栏目:Android代码|点击:

前言

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

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

最终效果图及思路

在这里插入图片描述
在这里插入图片描述

实现关键

气泡中间的两条边,分别是以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下载地址

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

上一篇:Android自定义流式布局实现淘宝搜索记录

栏    目:Android代码

下一篇:android杂记:C++文件的添加log方法分享

本文标题:Android未读消息拖动气泡示例代码详解(附源码)

本文地址:http://www.codeinn.net/misctech/157016.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有