QQ聊天列表粘性控件
2016-08-19 19:46
316 查看
QQ聊天列表粘性控件
应用场景:未读数据的清除等实现步骤:
1. 画静态图
先画个两个静态的圆圈,一个大的,一个小的 ,要画的这个图的坐标如下图,通过Path类将上图中的路径坐标一一填充进方法中即可画出下图形状,然后算出两个圆对应下图的坐标替换进去即可。protected void onDraw(Canvas canvas) { // 1. 画固定圆 canvas.drawCircle(200f, 200f, 10f, mPaint); // 2. 画拖动圆 canvas.drawCircle(100f, 100f, 15f, mPaint); // 3. 画中间连接线 Path path = new Path(); path.moveTo(300f, 300f); // 跳转到A点, path.quadTo(200f, 350f, 100f, 300f);// A到B 曲线,二次方贝塞尔曲线 path.lineTo(100f, 400f); // B到C 直线 path.quadTo(200f, 350f, 300,400); // C到D 曲线 path.close(); // D到A 直线 canvas.drawPath(path, mPaint); }
2. 把静止的值替换成变量
/** 固定圆的圆心 */ private PointF mStickCenter = new PointF(200f, 200f); /** 固定圆的半径 */ private float mStickRadius = 10f; /** 拖动圆的圆心 */ private PointF mDragCenter = new PointF(100f, 100f); /** 拖动圆的半径 */ private float mDragRadius = 15f; private PointF[] mStickPoints = new PointF[] { new PointF(300, 300), // A点 new PointF(300, 400) // D点 }; private PointF[] mDragPoints = new PointF[] { new PointF(100f, 300f), // B点 new PointF(100f, 400f) // C点 }; /** 控制点坐标 */ private PointF mCtrlPoint = new PointF(200f, 350f); protected void onDraw(Canvas canvas) { // 1. 画固定圆 canvas.drawCircle(mStickCenter.x, mStickCenter.y, mStickRadius, mPaint); // 2. 画拖动圆 canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, mPaint); // 3. 画中间连接线 Path path = new Path(); // 移动到A点 path.moveTo(mStickPoints[0].x, mStickPoints[0].y); // 曲线:A-->B path.quadTo(mCtrlPoint.x, mCtrlPoint.y, mDragPoints[0].x, mDragPoints[0].y); // 直线: B-->C path.lineTo(mDragPoints[1].x, mDragPoints[1].y); // 曲线:C-->d path.quadTo(mCtrlPoint.x, mCtrlPoint.y, mStickPoints[1].x, mStickPoints[1].y); // 直线:D-->A path.close(); canvas.drawPath(path, mPaint); }
3. 计算ABCD交叉点和控件点
通过圆心和半径算出四个附着点和控制点protected void onDraw(Canvas canvas) { // 计算直线的斜率 double dx = (mStickCenter.x - mDragCenter.x); double dy = (mStickCenter.y - mDragCenter.y); double lineK = 0; if (dx != 0) { // 除数不能为0 lineK = dy / dx; } // 计算ABCD四个交叉点 mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter, mDragRadius, lineK); mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter, mStickRadius, lineK); // 计算控件点 mCtrlPoint = GeometryUtil.getMiddlePoint(mDragCenter, mStickCenter); ... }
4. 响应按下和拖动事件
在onTouchEvent里面判断手指按下和抬起时将手指的坐标设置成拖拽圆的圆心并重绘界面。public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: mDragCenter.set(event.getX(), event.getY()); invalidate(); break; case MotionEvent.ACTION_UP: break; } return true; }
5. 绘制参考圆
protected void onDraw(Canvas canvas) { ... // 绘制参考圆:断开的最大范围 mPaint.setStyle(Style.STROKE); canvas.drawCircle(mStickCenter.x, mStickCenter.y, mMaxRange, mPaint); mPaint.setStyle(Style.FILL); }
6. 拖拽处理
思路分析:a. 拖动超出最大范围,则断开; (Move事件)
b. 超出了最大范围松开手, 则消失; (Up事件)
c. 没超出了最大范围松开手: 断开后,又放回最大范围内,则恢复显示; (Up事件)
d. 没超出了最大范围松开手: 拖拽没有超出最大范围松开手,则弹回去; (Up事件)
6.1. 拖动超出最大范围,则断开
public boolean onTouchEvent(MotionEvent event) { float radius; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mOutOfRange = false; case MotionEvent.ACTION_MOVE: ... // a. 拖动超出最大范围, 则断开; radius = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); if (radius > mMaxRange) { mOutOfRange = true; invalidate(); } break; } protected void onDraw(Canvas canvas) { ... // 2. 画拖动圆 canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, mPaint); // 断开了则不绘制固定圆和连接部分 if (!mOutOfRange) { // 1. 画固定圆 ... // 3. 画中间连接线 ... } ... }
6.2 超出最大范围松开则消失
public boolean onTouchEvent(MotionEvent event) { float radius; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mDisappear = false; case MotionEvent.ACTION_MOVE: ... case MotionEvent.ACTION_UP: // b. 在最大范围外松手,则消失; radius = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); if (radius > mMaxRange) { // 超出了最大范围 mDisappear = true; invalidate(); } else {} break; } // onDraw方法中: // 消失了就三部分都不绘制了 if (!mDisappear) { // 2、绘制拖动圆 canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, mPaint); // 断开了则不绘制固定圆和连接部分 if (!mOutOfRange) { // 1. 画固定圆 canvas.drawCircle(mStickCenter.x, mStickCenter.y, mStickRadius, mPaint); // 3. 画中间连接线 ... } }
6.3. 超出了最大范围松开手又放回去
public boolean onTouchEvent(MotionEvent event) { ... case MotionEvent.ACTION_UP: // b. 在最大范围外松手,则消失; radius = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); if (radius > mMaxRange) { // 超出最大范围 ... } else { // 没有超出了最大范围松开 if (mOutOfRange) { // 断开 // c. 断开后,又放回最大范围内松开,则恢复显示; mDragCenter.set(mStickCenter.x, mStickCenter.y); invalidate(); } else { // d. 拖拽没有超出最大范围松开手,则弹回去; } } break; } return true; }
6.4. 拖拽没有超出最大范围松开手则弹回去
public boolean onTouchEvent(MotionEvent event) { ... case MotionEvent.ACTION_UP: ... if (radius > mMaxRange) { // 超出了最大范围 ... } else { // 没有超出了最大范围松开 if (mOutOfRange) { // // c. 断开后,又放回最大范围内松开,则恢复显示; ... } else { // d. 拖拽没有超出最大范围松开手,则弹回去; final PointF start = new PointF(mDragCenter.x, mDragCenter.y); final PointF end = mStickCenter; ValueAnimator animator = ValueAnimator.ofFloat(1); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = animation.getAnimatedFraction(); PointF pointByPercent = GeometryUtil.getPointByPercent(start, end, percent); mDragCenter.set(pointByPercent); invalidate(); } }); animator.setInterpolator(new OvershootInterpolator(4)); animator.setDuration(300); animator.start(); } } break; } return true; }
7. 计算固定圆半径
protected void onDraw(Canvas canvas) { // 计算固定圆半径: 在一定范围内,拖动圆和固定圆的距离越远,固定圆的半径越小 float radius = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); float startRadius = mStickRadius; float endRadius = mStickRadius * 0.2f; if (radius > mMaxRange) { radius = mMaxRange; } float percent = radius / mMaxRange; float tempStickRadius = GeometryUtil.evaluateValue(percent, startRadius, endRadius); // 下面要改两个地方,替换为tempStickRadius ... }
以上是实现的主要代码:
完整源码:点击下载
相关文章推荐
- 仿手机QQ聊天列表滑动菜单删除和手势滑动返回的两种方式
- 实现类似QQ聊天列表的segment点击切换tableView的数据功能
- day08&09-通知机制(QQ聊天界面&QQ好友列表)
- Qt学习——聊天的QQ列表QToolBox类
- 【iOS基础控件 - 11】【Demo】模仿qq ,微信 UI 聊天界面
- QQ的粘性控件的实现原理
- MFC 列表控件CListCtrl加载类似QQ界面的头像与文字
- 【LibUIDK界面库系列文章】使用RichEdit制作QQ聊天记录控件
- 自定义listview 实现仿qq聊天列表左滑删除效果
- iOS开发UI— QQ好友列表(处理头部控件的点击)viewForHeaderInSection:
- QQ好友的列表恢复与聊天记录的恢复
- 遗忘qq密码后找回聊天记录和好友列表
- 【iOS 基础控件 - 12】 静态单元格 QQ功能列表
- QQ好友列表(处理头部控件的点击)viewForHeaderInSection:
- Qt学习——聊天的QQ列表QToolBox类
- 利用swipelistview完成qq聊天列表右滑删除功能
- [iOS基础控件 - 6.9.2] 静态单元格 QQ功能列表
- 5.模仿QQ粘性控件
- (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画
- 自定义控件仿QQ小红点,粘性控件,贝塞尔曲线绘制,值动画