欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-07-04 16:42:18
前言拖动清除未读消息可以说在很多应用中都很常见,也被用户广泛接受。本文是一个可以供参考的demo,希望能有帮助。提示:以下是本篇文章正文内容,下面案例可供参考最终效果图及思路实现关键:气泡中间的两条边...

前言

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

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

最终效果图及思路

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

实现关键

气泡中间的两条边,分别是以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未读消息拖动气泡内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!