真丶深红骑士
读完需要
15
分钟
速读仅需7分钟
作者:真丶深红骑士 链接:https://juejin.im/post/5d12e22e6fb9a07ee5662d82
1
前言
用QQ的时候,发现未读消息拖拽效果蛮有意思,就模仿了一下。
2
效果图
具体效果如下:
效果图具有以下特性:
- 小圆点拖拽是有范围的
- 在拖拽范围进行拖拽后释放小圆点会进行回弹后回到初始位置
- 拖拽的时候,中心的圆会慢慢变小,拖拽的圆大小不变,中间连接的部分越来越长并且越来细,直至消失
- 如果超出定义的拖拽范围后进行释放会有爆炸的效果并且消失
3
分析
3.1
组成
先分析这个视图的组成:
- 中心的小圆:一个固定的圆
- 跟着手指移动的小圆:一个拖拽的圆
- 两个圆的连接部分
- 两条直线(两个圆的直径),用来连接两条贝塞尔曲线,形成封闭图形
3.2
绘制
- 中心的小圆和拖拽的小圆绘制小圆相对比较简单,直接调用canvas.drawCircle即可,定点中心圆的圆心是固定的,拖拽圆的圆形是手指触摸屏幕的坐标。
- 两个圆之间连接的部分中间连接的部分其实是两条二阶贝塞尔曲线,具体分析如下:
那么(p1-p3)这条线可以用以下伪码来绘制:
代码语言:javascript复制1Path rPathLeft = new Path();
2rPathLeft.moveTo(P1.x,P1.y);
3rPathLeft.quadTo(M.x,M.y,P3.x,P3.y);
同理(P2-P4)这条线可以用以下伪代码来绘制:
代码语言:javascript复制1Path rPathRight = new Path();
2rPathRight.moveTo(P2.x,P2.y);
3rPathRight.quadTo(M.x,M.y,P4.x,P4.y);
- 两条直线两条直线就是分别是(P1-P2)和(P3-P4)
1rPathLeft.lineTo(P4.x,P4.y)
2rPathRight.lineTo(P2.x,P2.y)
绘制以上两条贝塞尔曲线和直线需要五个点:P1,P2,P3,P4,M,其中P1,P2,P3,P4是圆的切点,现在只知道两个圆的中心圆点O1和O2,那么怎么根据这两个点来求其余四个圆的切点呢?先分析:
根据上图可得知:
代码语言:javascript复制1tan(a) = y / x
2a = arctan(y / x)
3P3.x = X1-r2*sina
4P3.y = Y1-r2*cosa
5P1.x = X0-r1*sina
6P1.y = X0-r1*cosa
同理P2,P4也可以求出。
静态实现
下面先静态实现绘制图像,直接继承帧布局(FrameLayout)
代码语言:javascript复制 1public class RedPointView extends FrameLayout{
2 ......
3
4 //绘制自己孩子方法
5 //ViewGroup上绘制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法
6 protected void dispatchDraw(Canvas canvas){
7 super.dispatchDraw(canvas);
8
9 //先绘制固定圆
10 canvas.drawCircle(tCenterPointF.x,tCenterPointF.y,tCenterRadius,rPaint);
11 //再绘制拖拽圆
12 canvas.drawCircle(tDragPointF.x,tDragPointF.y,tDragRadius,rPaint);
13
14 float x = tCenterPointF.x - tDragPointF.x;
15 float y = tDragPointF.y - tCenterPointF.y;
16 //求a的角度
17 double a = Math.atan(y / x);
18
19 //中心圆的p1 x坐标偏移
20 float offsetX1 = (float) (tCenterRadius * Math.sin(a));
21 float offsetY1= (float) (tCenterRadius * Math.cos(a));
22
23 //拖拽圆的p2 x坐标偏移
24 float offsetX2 = (float) (tDragRadius * Math.sin(a));
25 float offsetY2= (float) (tDragRadius * Math.cos(a));
26
27 //p1的坐标
28 float p1_x = tCenterPointF.x - offsetX1;
29 float p1_y = tCenterPointF.y - offsetY1;
30
31
32 //p2的坐标
33 float p2_x = tCenterPointF.x offsetX1;
34 float p2_y = tCenterPointF.y offsetY1;
35
36 //p3的坐标
37 float p3_x = tDragPointF.x - offsetX2;
38 float p3_y = tDragPointF.y - offsetY2;
39
40 //p4的坐标
41 float p4_x = tDragPointF.x offsetX2;
42 float p4_y = tDragPointF.y offsetY2;
43 //控制点M的坐标
44 float controll_x = (tCenterPointF.x tDragPointF.x) / 2;
45 float controll_y = (tDragPointF.y tCenterPointF.y) / 2;
46 //创建Path来绘制路径
47 rPath = new Path();
48 //绘制路径方向:P1->P3->P4->P1
49 rPath.reset();
50 rPath.moveTo(p1_x,p1_y);
51 rPath.quadTo(controll_x,controll_y,p3_x,p3_y);
52 rPath.lineTo(p4_x,p4_y);
53 rPath.quadTo(controll_x,controll_y,p2_x,p2_y);
54 rPath.lineTo(p1_x,p1_y);
55 rPath.close();
56 canvas.drawPath(rPath,tPaint);
57
58 }
59
60}
布局文件直接ConstraintLayout嵌套这个自定义View即可:
代码语言:javascript复制 1<android.support.constraint.ConstraintLayout
2 xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context="com.knight.qq_redpoint.MainActivity">
8
9 <com.knight.qq_redpoint.RedPointView
10 android:layout_width="match_parent"
11 android:layout_height="match_parent"
12 app:layout_constraintTop_toTopOf="parent"
13 app:layout_constraintBottom_toBottomOf="parent"
14 app:layout_constraintLeft_toLeftOf="parent"
15 app:layout_constraintRight_toRightOf="parent"/>
16
17</android.support.constraint.ConstraintLayout>
效果图如下:
动态实现
静态效果绘制出来了,那么继续往下走,实现动态效果,实现动态无非是拖拽圆的切点和贝塞尔曲线的控制点在变化,而拖拽圆的圆心其实是触摸屏幕的坐标,那么其切点和控制点根据上一个步骤的公式来求出,下面直接在触摸方法onTouchEvent来处理:
代码语言:javascript复制
代码语言:javascript复制 1 public boolean onTouchEvent(MotionEvent event){
2 switch (event.getAction()){
3 case MotionEvent.ACTION_DOWN:
4 //event.getRawX:表示的是触摸点距离屏幕左边界的距离
5 //event.getRawY:表示的是触摸点距离屏幕上边界的距离
6 //event.getX()取相对于你触摸的view的左边的偏移(X坐标)
7 //event.getY()取相对于你触摸的view的顶边的偏移(Y坐标)
8 float originalDragX = event.getX();
9 float originalDragy = event.getY();
10 updateDragPoint(originalDragX,originalDragy);
11 break;
12 case MotionEvent.ACTION_MOVE:
13 float overDragX = event.getX();
14 float overDragy = event.getY();
15 //移动的时候不断更新拖拽圆的位置
16 updateDragPoint(overDragX,overDragy);
17 break;
18 }
19 return true;
20
21 }
22
23 //更新拖拽圆的圆心坐标
24 private void updateDragPoint(float x,float y){
25 tDragPointF.set(x,y);
26 postInvalidate();
27
28 }
效果图如下:
中心圆半径变化
仔细观察效果,发现随着拖拽距离的增加,中心圆的半径是越来越小的好像有那么一点点感觉了,但是远远还不够。那么我们可以定一个规则,拖拽距离和中心圆之间的关系,并且设置拖拽最大距离:
代码语言:javascript复制
代码语言:javascript复制 1 //中心的最小半径
2 private float minRadius = 8;
3 //默认拖拽最大距离
4 private float maxDistance = 160;
5
6 //计算拖动过程中中心圆的半径
7 private float changeCenterRadius() {
8 float mDistance_x = tDragPointF.x - tCenterPointF.x;
9 float mDistance_y = tDragPointF.y - tCenterPointF.y;
10 //两个圆之间的距离
11 float mDistance = (float) Math.sqrt(Math.pow(mDistance_x, 2) Math.pow(mDistance_y, 2));
12 //计算中心圆的半径 这里用拖拽圆默认的半径去减距离变化的长度(这里可以自己定义变化的半径)
13 float r = tDragRadius - minRadius * (mDistance / maxDistance);
14 //计算出半径如果小于最小的半径 就赋值最小半径
15 if (r < minRadius) {
16 r = minRadius;
17 }
18 return r;
19
20
21 }
最后在onDraw方法里,添加计算变化中心圆的半径即可:
代码语言:javascript复制
代码语言:javascript复制1 //绘制方法
2 protected void onDraw(Canvas canvas) {
3 super.onDraw(canvas);
4 canvas.save();
5 //绘制固定中心圆
6 tCenterRadius = changeCenterRadius();
7 canvas.drawCircle(tCenterPointF.x, tCenterPointF.y, tCenterRadius, rPaint);
8 ....
9 }
效果图如下:
距离限制
下面增加拖拽距离限制,当拖拽距离大于给定的距离时,中心圆就会消失,逻辑很简单,也就是在onTouchEvent里的ACTION_MOVE,计算两个圆的拖拽距离,如果超出给定的拖拽距离,就不绘制贝塞尔曲线和中心固定圆:
代码语言:javascript复制
代码语言:javascript复制 1 //标识 拖拽距离是否大于规定的拖拽范围
2 private boolean isOut;
3
4 //标识 如果超出拖拽范围
5 private boolean isOverStep;
6 //绘制方法
7 protected void onDraw(Canvas canvas) {
8 super.onDraw(canvas);
9 canvas.save();
10
11 if(!isOut){
12 //绘制固定中心圆
13 tCenterRadius = changeCenterRadius();
14 canvas.drawCircle(tCenterPointF.x, tCenterPointF.y, tCenterRadius, rPaint);
15 .....
16 }
17 //一旦超出给定的拖拽距离 就绘制拖拽圆
18 if(!isOverStep){
19 canvas.drawCircle(tDragPointF.x,tDragPointF.y,tDragRadius,rPaint);
20 }
21 }
22
23 //重写onTouchEvent方法
24 public boolean onTouchEvent(MotionEvent event) {
25 switch (event.getAction()) {
26 ........
27 case MotionEvent.ACTION_MOVE:
28 float overDragX = event.getX();
29 float overDragy = event.getY();
30 //移动的时候不断更新拖拽圆的位置
31 updateDragPoint(overDragX, overDragy);
32 float tDragDistance = getDistanceTwo(tCenterPointF,tDragPointF);
33 //判断如果拖拽距离大于给定距离时
34 if(tDragDistance > maxDistance){
35 isOut = true;
36 }else{
37 //这里要注意 不能赋值isOut为false 因为一旦超出给定的拖拽距离就没办法恢复了
38 isOverStep = false;
39 }
40 break;
41 }
42 return true;
43
44 }
45
46 //计算两个圆之间的距离
47 private float getDistanceTwo(PointF tCenterPointF,PointF tDragPointF){
48 return (float) Math.sqrt(Math.pow(tCenterPointF.x - tDragPointF.x,2) Math.pow(tCenterPointF.y - tDragPointF.y,2));
49 }
效果图如下:
上面只做了超出拖拽范围的效果,下面添加没有超出拖拽范围效果,松开手后拖拽圆会回弹原来的位置,那就要在MotionEvent.ACTION_UP做处理:
代码语言:javascript复制
代码语言:javascript复制 1 //重写onTouchEvent方法
2 public boolean onTouchEvent(MotionEvent event) {
3 switch (event.getAction()) {
4 ....
5 case MotionEvent.ACTION_UP:
6 getDistanceTwo(tCenterPointF,tDragPointF);
7 //这里要判断
8 if(!isOut){
9 //没有超出
10 kickBack();
11 }
12 postInvalidate();
13 break;
14 }
15 return true;
16
17 }
18
19 /**
20 * 拖拽圆回弹动画
21 *
22 */
23 private void kickBack() {
24 final PointF initPoint = new PointF(tDragPointF.x,
25 tDragPointF.y);
26 final PointF finishPoint = new PointF(tCenterPointF.x,
27 tCenterPointF.y);
28 //值从0平滑过渡1
29 ValueAnimator animator = ValueAnimator.ofFloat(0.0f,1.0f);
30 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
31
32 @Override
33 public void onAnimationUpdate(ValueAnimator animation) {
34 //获取动画执行进度
35 float rFraction = animation.getAnimatedFraction();
36 //更新拖拽圆的圆心
37 PointF updateDragPoint = getPoint(
38 initPoint, finishPoint, rFraction);
39 updateDragPoint(updateDragPoint.x, updateDragPoint.y);
40 }
41 });
42 //设置动画插值器
43 animator.setInterpolator(new OvershootInterpolator(3.0f));
44 //动画时间
45 animator.setDuration(500);
46 animator.start();
47 }
48
49
50 /**
51 *
52 * 根据百分比获取两点之间的某个点坐标
53 * @param initPoint 初识圆
54 * @param finishPoint 最终圆
55 * @param percent 百分比
56 * @return
57 *
58 */
59 public PointF getPoint(PointF initPoint, PointF finishPoint, float percent) {
60 return new PointF(getValue(initPoint.x , finishPoint.x,percent), getValue(initPoint.y , finishPoint.y,percent));
61 }
62
63 /**
64 * 获取分度值
65 * @param start
66 * @param finish
67 * @param fraction
68 * @return
69 */
70 public float getValue(Number start, Number finish,float fraction){
71 return start.floatValue() (finish.floatValue() - start.floatValue()) * fraction;
72 }
效果图:
增加爆炸效果
当拖拽圆超出拖拽范围后,会有一个爆炸效果后并消失,下面添加爆炸效果:
代码语言:javascript复制
代码语言:javascript复制 1 //初始化爆炸图片
2 private int[] explodeImgae = new int[]{
3 R.mipmap.explode_1,
4 R.mipmap.explode_2,
5 R.mipmap.explode_3,
6 R.mipmap.explode_4,
7 R.mipmap.explode_5
8 };
9 //爆炸ImageView
10 private ImageView explodeImage;
11复制代码并在init初始化方法里添加对这爆炸图像:
12 //添加爆炸图像
13 explodeImage = new ImageView(getContext());
14 //设置布局参数
15 LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
16 explodeImage.setLayoutParams(lp);
17 explodeImage.setImageResource(R.mipmap.explode_1);
18 //一开始不显示
19 explodeImage.setVisibility(View.INVISIBLE);
20 //增加到viewGroup中
21 addView(explodeImage);
并实现播放动画方法:
代码语言:javascript复制
代码语言:javascript复制 1 /**
2 *
3 * 超过拖拽范围外显示爆炸效果
4 *
5 */
6 private void showExplodeImage(){
7 //属性动画
8 ValueAnimator animator = ValueAnimator.ofInt(0,explodeImgaes.length - 1);
9 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
10 @Override
11 public void onAnimationUpdate(ValueAnimator animation) {
12 //不断更新图像变化
13 explodeImage.setBackgroundResource(explodeImgaes[(int) animation.getAnimatedValue()]);
14 }
15 });
16 //为动画添加监听
17 animator.addListener(new AnimatorListenerAdapter() {
18 @Override
19 public void onAnimationCancel(Animator animation) {
20 super.onAnimationCancel(animation);
21 }
22
23 @Override
24 public void onAnimationEnd(Animator animation) {
25 super.onAnimationEnd(animation);
26 //结束了 把图像设置不可见状态
27 explodeImage.setVisibility(View.GONE);
28 }
29
30 @Override
31 public void onAnimationRepeat(Animator animation) {
32 super.onAnimationRepeat(animation);
33 }
34
35 @Override
36 public void onAnimationStart(Animator animation) {
37 super.onAnimationStart(animation);
38 //开始时 设置为可见
39 explodeImage.setVisibility(View.VISIBLE);
40 }
41
42 @Override
43 public void onAnimationPause(Animator animation) {
44 super.onAnimationPause(animation);
45 }
46
47 @Override
48 public void onAnimationResume(Animator animation) {
49 super.onAnimationResume(animation);
50 }
51 });
52 //时间
53 animator.setDuration(600);
54 //播放一次
55 animator.setRepeatMode(ValueAnimator.RESTART);
56 //差值器
57 animator.setInterpolator(new OvershootInterpolator());
58 animator.start();
59 }
在MotionEvent.ACTION_UP里:
代码语言:javascript复制
代码语言:javascript复制 1 case MotionEvent.ACTION_UP:
2 getDistanceTwo(tCenterPointF,tDragPointF);
3 //这里要判断
4 if(!isOut){
5 //没有超出
6 kickBack();
7 }
8 if(isOut){
9 //抬起标识
10 isOverandUp = true;
11 //让爆炸图片在原点中央
12 explodeImage.setX(event.getX() - tDragRadius);
13 explodeImage.setY(event.getY() - tDragRadius);
14 //如果中心圆和拖拽圆大于拖拽距离 就播放爆炸
15 if(getDistanceTwo(tCenterPointF,tDragPointF) > maxDistance){
16 showExplodeImage();
17 }
18 //这里是如果拖拽圆和中心圆距离已经超出拖拽距离 然后又把拖拽圆移动与中心圆大于30 还是会爆炸
19 if(getDistanceTwo(tCenterPointF,tDragPointF) >=30){
20 showExplodeImage();
21 }
22
23 }
24 postInvalidate();
25 break;
在dispatchView超出拖拽距离到小于恢复中心圆的距离逻辑:
代码语言:javascript复制
代码语言:javascript复制 1 if(isOut){
2 //如果一开始超出拖拽范围 后面又移动拖拽圆与中心圆的距离少于30,就恢复中心圆位置
3 if(getDistanceTwo(tCenterPointF,tDragPointF) < 30 && isOverandUp){
4 canvas.drawCircle(tCenterPointF.x, tCenterPointF.y, tCenterRadius, rPaint);
5 isOut = false;
6 isOverandUp = false;
7 }
8
9
10 }
11
12
13 //一旦超出给定的拖拽距离 就绘制拖拽圆
14 if(!isOverStep){
15 //如果超出并且抬起
16 if(!isOverandUp && isOut){
17 canvas.drawCircle(tDragPointF.x,tDragPointF.y,tDragRadius,rPaint);
18 }
19
20 }
效果图如下:
4
添加到ListView
4.1
添加到WindowManager
上面所实现的效果还远远不够,怎么像QQ那样,在ListView或者Recycleview里小圆点能自由在屏幕内拖拽呢?因为view只能在它的父控件内绘制,所以也只能在自己的列表内移动,那怎么能在全屏拖拽呢?只能借助WindowManager,也就是当将要拖拽的圆点添加到windowManager,并且设置触摸监听,自定义拖拽view从继承ViewGroup变为继承View
代码语言:javascript复制
构造函数将拖拽的view和WindowManager对象传进来,并初始化一些参数:
代码语言:javascript复制 1 //初始化小圆
2 private void init() {
3 //手动测量
4 dragView.measure(1,1);
5 dragViewWidth = dragView.getMeasuredWidth() / 2;
6 dragViewHeight = dragView.getMeasuredHeight() / 2;
7
8 tDragRadius = dragViewHeight;
9 //中心圆的半径
10 tCenterRadius = SystemUtil.dp2px(context,8);
11 //最大拖拽距离
12 maxDistance = SystemUtil.dp2px(context,80);
13 //最小半径
14 minRadius = SystemUtil.dp2px(context,3);
15
16 //布局参数
17 params = new WindowManager.LayoutParams();
18 //背景透明
19 params.format = PixelFormat.TRANSLUCENT;
20 params.height = WindowManager.LayoutParams.WRAP_CONTENT;
21 params.width = WindowManager.LayoutParams.WRAP_CONTENT;
22 //以左上角为基准
23 params.gravity = Gravity.TOP | Gravity.LEFT;
24
25 }
代码语言:javascript复制
4.2
更新拖拽view的位置
在上面例子中更新拖拽圆updateDragPoint的方法,也同样通过WindowManager.updateViewLayout来更新拖拽view的的位置:
代码语言:javascript复制
代码语言:javascript复制 1 /**
2 * 更新拖拽圆心坐标
3 * @param x
4 * @param y
5 */
6 private void updateDragPoint(float x, float y) {
7 tDragPointF.set(x, y);
8 changeManagerView(x,y);
9 postInvalidate();
10
11 }
12
13 /**
14 * 重新绘制拖拽圆的布局
15 * @param x x坐标
16 * @param y y坐标
17 */
18 private void changeManagerView(float x,float y){
19 params.x = (int)(x - dragViewWidth);
20 params.y = (int)(y - dragViewHeight - statusBarHeight);
21 windowManager.updateViewLayout(dragView,params);
22 }
代码语言:javascript复制
4.3
添加状态监听
增加拖拽圆和中心圆的拖拽情况监听:
代码语言:javascript复制
代码语言:javascript复制 1public interface DragViewStatusListener {
2
3 /**
4 * 在拖拽范围外移动
5 *
6 * @param dragPoint
7 */
8 void outDragMove(PointF dragPoint);
9
10 /**
11 * 在拖拽范围外移动
12 * 产生爆炸效果
13 *
14 */
15 void outDragMoveUp(PointF dragPoint);
16
17 /**
18 * 在拖拽范围内移动
19 *
20 * @param dragPoint
21 */
22 void inDragUp(PointF dragPoint);
23
24
25 /**
26 * 当移出拖拽范围 后拖拽到范围内 恢复中心圆
27 *
28 */
29 void recoverCenterPoint(PointF centerPoint);
30
31
32}
在对应触发的情况下实现监听回调,如爆炸的动画:
代码语言:javascript复制
代码语言:javascript复制 1 case MotionEvent.ACTION_UP:
2 getDistanceTwo(tCenterPointF,tDragPointF);
3 //这里要判断
4 if(!isOut){
5 //没有超出
6 kickBack();
7 }
8 if(isOut){
9 //抬起标识
10 isOverandUp = true;
11 //让爆炸图片在原点中央
12 //explodeImage.setX(event.getX() - tDragRadius);
13 //explodeImage.setY(event.getY() - tDragRadius);
14 //如果中心圆和拖拽圆大于拖拽距离 就播放爆炸
15 if(getDistanceTwo(tCenterPointF,tDragPointF) > maxDistance){
16 //这里监听做爆炸效果
17 if(dragViewStatusListener != null){
18 dragViewStatusListener.outDragMoveUp(tDragPointF);
19 }
20 }
21 //这里是如果拖拽圆和中心圆距离已经超出拖拽距离 然后又把拖拽圆移动与中心圆大于30 还是会爆炸
22 if(getDistanceTwo(tCenterPointF,tDragPointF) >=30){
23 if(dragViewStatusListener != null){
24 dragViewStatusListener.outDragMoveUp(tDragPointF);
25 }
26 }
27 }
代码语言:javascript复制
4.4
新建中间桥梁
新建一个类,主要用来辅助,主要用来创建拖拽自定义view和创建WindowManager对象初始化数据,并且作出各种情况下(在范围内拖拽,范围外拖拽)的逻辑和爆炸逻辑,主要代码在BetterRedPointViewControl中
代码语言:javascript复制 1public class BetterRedPointViewControl implements View.OnTouchListener,DragViewStatusListener{
2 .......
3
4 @Override
5 public boolean onTouch(View v, MotionEvent event) {
6 int action = MotionEventCompat.getActionMasked(event);
7 if(action == MotionEvent.ACTION_DOWN){
8
9 ViewParent parent = v.getParent();
10 if(parent == null){
11 return false;
12 }
13
14 parent.requestDisallowInterceptTouchEvent(true);
15 statusHeight = SystemUtil.getStatusBarHeight(showView);
16 showView.setVisibility(View.INVISIBLE);
17 dragView = LayoutInflater.from(context).inflate(mDragViewId,null,false);
18 //获取文本内容
19 getText();
20 windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
21 //每当触摸的时候就创建拖拽的小圆
22 betterRedPointView = new BetterRedPointView(context,dragView,windowManager);
23 //初始化数据
24 init();
25 //设置监听回调
26 betterRedPointView.setDragViewStatusListener(this);
27 //添加到窗体进行显示
28 windowManager.addView(betterRedPointView,params);
29 windowManager.addView(dragView,params);
30
31 }
32 betterRedPointView.onTouchEvent(event);
33 return true;
34 }
35 ......
36}
代码语言:javascript复制
4.5
调用
在Recycleview内执行调用即可,主要代码在RecycleviewAdapter中
代码语言:javascript复制 1public class RecycleviewAdapter extends RecyclerView.Adapter<ItemHolder> {
2 ......
3
4 @Override
5 public void onBindViewHolder(@NonNull ItemHolder itemHolder, final int i) {
6 itemHolder.tv_dragView.setText(String.valueOf(i));
7
8 Glide.with(mContext).load(R.mipmap.iv_image).apply(RequestOptions.bitmapTransform(new CircleCrop()).override(200,200)).into(itemHolder.iv_head);
9 //是否隐藏要拖拽的view
10 if(needRemoveList.contains(i)){
11 itemHolder.tv_dragView.setVisibility(View.GONE);
12 }
13 else {
14 itemHolder.tv_dragView.setVisibility(View.VISIBLE);
15 itemHolder.tv_dragView.setText(String.valueOf(i));
16 }
17 //一个是拖拽的view 一个是拖拽的view布局
18 new BetterRedPointViewControl(mContext, itemHolder.tv_dragView, R.layout.includeview, new BetterRedPointViewControl.DragStatusListener() {
19 /**
20 * 在范围内
21 *
22 */
23 @Override
24 public void inScope() {
25 notifyDataSetChanged();
26 }
27
28 /**
29 * 在范围外
30 *
31 */
32 @Override
33 public void outScope() {
34 needRemoveList.add(i);
35 notifyDataSetChanged();
36
37 }
38 });
39 }
40}
代码语言:javascript复制
4.6
最终效果
效果图如下:
5
项目例子
github地址:
https://github.com/KnightAndroid/QQ_RedPoint