国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android高仿QQ小紅點功能

2019-12-12 02:38:34
字體:
來源:轉載
供稿:網友

先給大家展示下效果圖:

代碼已上傳至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來處理各種情況,代碼如下:

@Overridepublic 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小紅點功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宜宾市| 江油市| 明溪县| 新蔡县| 德庆县| 临沭县| 吐鲁番市| 武威市| 虞城县| 温宿县| 灵璧县| 石泉县| 阿拉善盟| 蒲江县| 博乐市| 井研县| 贵溪市| 沁水县| 东乌珠穆沁旗| 汉阴县| 来安县| 开封市| 延吉市| 祥云县| 泰顺县| 新龙县| 黄山市| 武安市| 万荣县| 麻栗坡县| 镇康县| 玛沁县| 阜康市| 永城市| 威远县| 阳泉市| 河南省| 建宁县| 梅河口市| 芮城县| 宁河县|