Android高仿QQ小红点功能

先给大家展示下效果图:

代码已上传至Github:高仿QQ小红点,如对您有帮助,欢迎star~感谢

绘制贝塞尔曲线:

主要是当在一定范围内拖拽时算出固定圆和拖拽圆的外切直线以及对应的切点,就可以通过path.quadTo()来绘制二阶贝塞尔曲线了~

整体思路:

1、当小红点静止时,什么都不做,只需要给自定义小红点QQBezierView(extends TextView)添加一个.9文件当背景即可

2、当滑动时,通过getRootView()获得顶级根View,然后new一个DragView ( extends View ) 来绘制各种状态时的小红点,并且通过getRootView().addView()的方式把DragView 加进去,这样DragView 就可以实现全屏滑动了

实现过程:

自定义QQBezierView ( extends TextView ) 并复写onTouchEvent来处理各种情况,代码如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
  //获得根View
  View rootView = getRootView();
  //获得触摸位置在全屏所在位置
  float mRawX = event.getRawX();
  float mRawY = event.getRawY();
  switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      //请求父View不拦截
      getParent().requestDisallowInterceptTouchEvent(true);
      //获得当前View在屏幕上的位置
      int[] cLocation = new int[2];
      getLocationOnScreen(cLocation);
      if (rootView instanceof ViewGroup) {
        //初始化拖拽时显示的View
        dragView = new DragView(getContext());
        //设置固定圆的圆心坐标
        dragView.setStickyPoint(cLocation[0] + mWidth / 2, cLocation[1] + mHeight / 2, mRawX, mRawY);
        //获得缓存的bitmap,滑动时直接通过drawBitmap绘制出来
        setDrawingCacheEnabled(true);
        Bitmap bitmap = getDrawingCache();
        if (bitmap != null) {
          dragView.setCacheBitmap(bitmap);
          //将DragView添加到RootView中,这样就可以全屏滑动了
          ((ViewGroup) rootView).addView(dragView);
          setVisibility(INVISIBLE);
        }
      }
      break;
    case MotionEvent.ACTION_MOVE:
      //请求父View不拦截
      getParent().requestDisallowInterceptTouchEvent(true);
      if (dragView != null) {
        //更新DragView的位置
        dragView.setDragViewLocation(mRawX, mRawY);
      }
      break;
    case MotionEvent.ACTION_UP:
      getParent().requestDisallowInterceptTouchEvent(false);
      if (dragView != null) {
        //手抬起时来判断各种情况
        dragView.setDragUp();
      }
      break;
  }
  return true;
}

上面代码注释已经很详细了,总结一下就是通过内部拦截法来请求父View是否拦截分发事件,并通过event.getRawX()和event.getRawY()来不断更新DragView的位置,那么DragView都做了哪些事呢,接下来就看一下DragView,DragView是QQBezierView 的一个内部View类:

 private int mState;//当前红点的状态
 private static final int STATE_INIT = 0;//默认静止状态
 private static final int STATE_DRAG = 1;//拖拽状态
 private static final int STATE_MOVE = 2;//移动状态
 private static final int STATE_DISMISS = 3;//消失状态

首先声明了小红点的四种状态,静止状态,拖拽状态,移动状态和消失状态。

在QQBezierView 的onTouchEvent的DOWN事件中调用了setStickyPoint()方法:

/**
 * 设置固定圆的圆心和半径
 * @param stickyX 固定圆的X坐标
 * @param stickyY 固定圆的Y坐标
 */
 public void setStickyPoint(float stickyX, float stickyY, float touchX, float touchY) {
   //分别设置固定圆和拖拽圆的坐标
   stickyPointF.set(stickyX, stickyY);
   dragPointF.set(touchX, touchY);
   //通过两个圆点算出圆心距,也是拖拽的距离
   dragDistance = MathUtil.getTwoPointDistance(dragPointF, stickyPointF);
   if (dragDistance <= maxDistance) {
     //如果拖拽距离小于规定最大距离,则固定的圆应该越来越小,这样看着才符合实际
     stickRadius = (int) (defaultRadius - dragDistance / 10) < 10 ? 10 : (int) (defaultRadius - dragDistance / 10);
     mState = STATE_DRAG;
   } else {
     mState = STATE_INIT;
   }
 }

接着,在QQBezierView 的onTouchEvent的MOVE事件中调用了setDragViewLocation()方法:

 /**
 * 设置拖拽的坐标位置
 *
 * @param touchX 拖拽时的X坐标
 * @param touchY 拖拽时的Y坐标
 */
 public void setDragViewLocation(float touchX, float touchY) {
   dragPointF.set(touchX, touchY);
   //随时更改圆心距
   dragDistance = MathUtil.getTwoPointDistance(dragPointF, stickyPointF);
   if (mState == STATE_DRAG) {
    if (isInsideRange()) {
       stickRadius = (int) (defaultRadius - dragDistance / 10) < 10 ? 10 : (int) (defaultRadius - dragDistance / 10);
     } else {
       mState = STATE_MOVE;
       if (onDragListener != null) {
         onDragListener.onMove();
       }
     }
   }
   invalidate();
 }

最后在QQBezierView 的onTouchEvent的UP事件中调用了setDragUp()方法:

public void setDragUp() {
  if (mState == STATE_DRAG && isInsideRange()) {
    //拖拽状态且在范围之内
    startResetAnimator();
   } else if (mState == STATE_MOVE) {
     if (isInsideRange()) {
      //在范围之内 需要RESET
      startResetAnimator();
    } else {
      //在范围之外 消失动画
      mState = STATE_DISMISS;
      startExplodeAnim();
    }
  }
}

最后来看下DragView的onDraw方法,拖拽时的贝塞尔曲线以及拖拽滑动时的状态都是通过onDraw实现的:

@Override
 protected void onDraw(Canvas canvas) {
   if (isInsideRange() && mState == STATE_DRAG) {
     mPaint.setColor(Color.RED);
     //绘制固定的小圆
     canvas.drawCircle(stickyPointF.x, stickyPointF.y, stickRadius, mPaint);
     //首先获得两圆心之间的斜率
     Float linK = MathUtil.getLineSlope(dragPointF, stickyPointF);
     //然后通过两个圆心和半径、斜率来获得外切线的切点
     PointF[] stickyPoints = MathUtil.getIntersectionPoints(stickyPointF, stickRadius, linK);
     dragRadius = (int) Math.min(mWidth, mHeight) / 2;
     PointF[] dragPoints = MathUtil.getIntersectionPoints(dragPointF, dragRadius, linK);
     mPaint.setColor(Color.RED);
     //二阶贝塞尔曲线的控制点取得两圆心的中点
     controlPoint = MathUtil.getMiddlePoint(dragPointF, stickyPointF);
     //绘制贝塞尔曲线
     mPath.reset();
     mPath.moveTo(stickyPoints[0].x, stickyPoints[0].y);
     mPath.quadTo(controlPoint.x, controlPoint.y, dragPoints[0].x, dragPoints[0].y);
     mPath.lineTo(dragPoints[1].x, dragPoints[1].y);
     mPath.quadTo(controlPoint.x, controlPoint.y, stickyPoints[1].x, stickyPoints[1].y);
     mPath.lineTo(stickyPoints[0].x, stickyPoints[0].y);
     canvas.drawPath(mPath, mPaint);
   }
   if (mCacheBitmap != null && mState != STATE_DISMISS) {
     //绘制缓存的Bitmap
     canvas.drawBitmap(mCacheBitmap, dragPointF.x - mWidth / 2,
            dragPointF.y - mHeight / 2, mPaint);
   }
   if (mState == STATE_DISMISS && explodeIndex < explode_res.length) {
     //绘制小红点消失时的爆炸动画
     canvas.drawBitmap(bitmaps[explodeIndex], dragPointF.x - mWidth / 2, dragPointF.y - mHeight / 2, mPaint);
   }
 }

PS:最开始使用的是 Android:clipChildren=”false” 这个属性,如果父View只是一个普通的ViewGroup(如LinearLayout、RelativeLayout等),此时在父View中设置android:clipChildren=”false”后,子View就可以超出自己的范围,在ViewGroup中也可以滑动了,此时也没问题;但是当是RecycleView时,只要ItemView设置了background属性,滑动时的DragView就会显示在background的下面了,好蛋疼~如有知其原因的还望不吝赐教~

最后再贴下源码下载地址:Android高仿QQ小红点

以上所述是小编给大家介绍的Android高仿QQ小红点功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android自定义ActionProvider ToolBar实现Menu小红点

    今天的几个目标: 1. 自定义ActionProvider 2. Toolbar ActionBar自定义Menu 3. Toolbar ActionBar 右侧Menu添加角标(Toolbar ActionBar Menu添加小红点) 源代码在文章末尾. -------------------------------------------------------------------------------- 效果预览 自定义Menu后不影响原生MD的任何效果.可以通过外部来控制显示的文字

  • Android应用图标上的小红点Badge实践代码

    现在Android中有许多的应用仿苹果的在应用图标上显示小红点.当然有着一些手机ROM对小红点的支持,比如小米,三星等.google的api是没有提供这项工能的,这项功能一般都是厂商自己定制的,所以让开发者着实头痛,我也是弄了2天,不是所有的机型都可以.以后再一点点完善吧.希望对读文章的人,或也在受此困惑的人有点帮助! 效果图:(DODO那个是我的应用,小米miui8测试) 直接上代码吧,代码中有注释: 直接上代码吧,代码中有注释: BadgeUtil类: public class BadgeU

  • Android高仿QQ小红点功能

    先给大家展示下效果图: 代码已上传至Github:高仿QQ小红点,如对您有帮助,欢迎star~感谢 绘制贝塞尔曲线: 主要是当在一定范围内拖拽时算出固定圆和拖拽圆的外切直线以及对应的切点,就可以通过path.quadTo()来绘制二阶贝塞尔曲线了~ 整体思路: 1.当小红点静止时,什么都不做,只需要给自定义小红点QQBezierView(extends TextView)添加一个.9文件当背景即可 2.当滑动时,通过getRootView()获得顶级根View,然后new一个DragView (

  • Android 高仿QQ 沉浸式状态栏

    前言: 在进入今天正题前,还是老样子先谈谈感想吧,最近感觉整个都失去了方向感,好迷茫!找工作又失败了,难道Android真的饱和了?这两天我一直没出门,除了下楼哪外卖就是宅宿舍了,静想了许久,我还是不能忘了初心,我相信我找不到工作的原因有很多,最关键的还是要技术够硬才行啊,奔跑吧孩子!接下来我就给大家介绍怎样快速打造沉浸式状态栏吧,虽然感觉有点相见恨晚,但其实不完! 一:何为沉浸式状态栏? 沉浸式状态栏是Google从Android 4.4开始,给我们开发者提供的一套能透明的系统ui样式,这样样

  • Android 高仿QQ图片选择器

    当做一款APP,需要选择本地图片时,首先考虑的无疑是系统相册,但是Android手机五花八门,再者手机像素的提升,大图无法返回等异常因数,导致适配机型比较困难,微信.QQ都相继的在自己的APP里集成了图片选择功能,放弃了系统提供的图片选择器,这里仿造QQ做了一个本地图片选择器,PS:之前有人说"仿"写成"防"了,今儿特意注意了下,求不错. 先上一张效果图,无图无真相啊~~~ 实现的效果大概是这样的: 1.单选:跳转到本地图片选择文件夹,选择文件夹后,进入到该文件夹下

  • 使用RecylerView完成拖动排序高仿qq侧滑删除功能

    最近使用到Recylerview完成拖动排序,侧滑删除,在此记录一下. 需要使用到:ItemTouchHelper.Callback这个类. 效果图: 在有RecylerView的Activity中,除了设置Adapter还需要做的事情有: MyItemTouchHelperCallback callback = new MyItemTouchHelperCallback(adapter); //此类继承ItemTouchHelper.Callback,这是帮助处理RecylerView拖动侧滑

  • Android 高仿微信朋友圈拍照上传功能

    模仿微信朋友圈发布动态,输入文字支持文字多少高度自增,有一个最小输入框高度,输入文字有限制,不过这些都很easy! 1. PhotoPicker的使用 这是一个支持选择多张图片,点击图片放大,图片之间左右滑动互相切换的库,同时支持图片删除的库,效果类似微信. (1) 添加PhotoPicker的架包 (2) 使用 选择图片:安卓6.0以后需要在代码中添加读写sd卡和相机的权限 当然清单文件中也需要添加的 PhotoPicker.builder() .setPhotoCount(maxPhoto)

  • Android使用Item Swipemenulistview实现仿QQ侧滑删除功能

    大家都用过QQ,肯定有人好奇QQ滑动删除Item的效果是怎样实现的,其实我们使用Swipemenulistview就可以简单的实现.先看看我们项目中的效果: 使用的时候可以把Swipemenulistview作为一个library,也可以把Swipemenulistview的源码拷贝到我们的项目中来,使用步骤大致可以分为三步:1.在布局中配置:2.在Java代码中初始化配置:3.按钮点击事件的处理  1.在布局中配置 xml布局文件中只需要简单使用这个自定义的ListView就行了,需要注意的是

  • Android 高仿微信支付数字键盘功能

    现在很多app的支付.输入密码功能,都已经开始使用自定义数字键盘,不仅更加方便.其效果着实精致. 下面带着大家学习下,如何高仿微信的数字键盘,可以拿来直接用在自身的项目中. 先看下效果图: 1. 自定义布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

  • 利用百度地图Android sdk高仿微信发送位置功能及遇到的问题

    接触了百度地图开发平台半个月了,这2天试着模仿了微信给好友发送位置功能,对百度地图的操作能力又上了一个台阶 我在实现这个功能的时候,遇到一些困难,可能也是别人将会遇到的困难,特在此列出 1.在微信发送功能中,不管用户如何拖拽地图,总有个覆盖物固定了MapView中央,怎么实现? 其实这很容易实现,只要MapView的布局文件中,将一个ImageView覆盖在MapView的中央,就能够实现不管用户如何拖拽地图,覆盖物(ImageView)总固定总MapView中央 2.如何获取MapView中央

  • Android开发仿QQ空间根据位置弹出PopupWindow显示更多操作效果

    我们打开QQ空间的时候有个箭头按钮点击之后弹出PopupWindow会根据位置的变化显示在箭头的上方还是下方,比普通的PopupWindow弹在屏幕中间显示好看的多. 先看QQ空间效果图: 这个要实现这个效果可以分几步进行 1.第一步自定义PopupWindow,实现如图的样式,这个继承PopupWindow自定义布局很容易实现 2.得到点击按钮的位置,根据位置是否在屏幕的中间的上方还是下方,将PopupWindow显示在控件的上方或者下方 3.适配问题,因为PopupWindow上面的操作列表

  • Android 高仿斗鱼滑动验证码

    如下图.在Android上实现起来就不太容易,有些效果还是不如web端酷炫.) 我们的Demo,Ac娘镇楼 (图很渣,也忽略底下的SeekBar,这不是重点) 一些动画,效果录不出来了,大家可以去斗鱼web端看一下,然后下载Demo看一下,效果还是可以的. 代码 传送门: https://github.com/mcxtzhang/SwipeCaptcha 我们的Demo和web端基本上一样. 那么本控件包含不仅包含以下功能: 随机区域起点(左上角x,y)生成一个验证码阴影.验证码拼图 凹凸图形会

随机推荐