欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android高仿QQ小紅點(diǎn)功能

 更新時(shí)間:2017年06月20日 09:43:09   作者:-小馬快跑-  
這篇文章主要介紹了Android高仿QQ小紅點(diǎn)功能的相關(guān)資料,需要的朋友可以參考下

先給大家展示下效果圖:

代碼已上傳至Github:高仿QQ小紅點(diǎn),如對(duì)您有幫助,歡迎star~感謝

繪制貝塞爾曲線:

主要是當(dāng)在一定范圍內(nèi)拖拽時(shí)算出固定圓和拖拽圓的外切直線以及對(duì)應(yīng)的切點(diǎn),就可以通過path.quadTo()來繪制二階貝塞爾曲線了~

整體思路:

1、當(dāng)小紅點(diǎn)靜止時(shí),什么都不做,只需要給自定義小紅點(diǎn)QQBezierView(extends TextView)添加一個(gè).9文件當(dāng)背景即可

2、當(dāng)滑動(dòng)時(shí),通過getRootView()獲得頂根View,然后new一個(gè)DragView ( extends View ) 來繪制各種狀態(tài)時(shí)的小紅點(diǎn),并且通過getRootView().addView()的方式把DragView 加進(jìn)去,這樣DragView 就可以實(shí)現(xiàn)全屏滑動(dòng)了

實(shí)現(xiàn)過程:

自定義QQBezierView ( extends TextView ) 并復(fù)寫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:
      //請(qǐng)求父View不攔截
      getParent().requestDisallowInterceptTouchEvent(true);
      //獲得當(dāng)前View在屏幕上的位置
      int[] cLocation = new int[2];
      getLocationOnScreen(cLocation);
      if (rootView instanceof ViewGroup) {
        //初始化拖拽時(shí)顯示的View
        dragView = new DragView(getContext());
        //設(shè)置固定圓的圓心坐標(biāo)
        dragView.setStickyPoint(cLocation[0] + mWidth / 2, cLocation[1] + mHeight / 2, mRawX, mRawY);
        //獲得緩存的bitmap,滑動(dòng)時(shí)直接通過drawBitmap繪制出來
        setDrawingCacheEnabled(true);
        Bitmap bitmap = getDrawingCache();
        if (bitmap != null) {
          dragView.setCacheBitmap(bitmap);
          //將DragView添加到RootView中,這樣就可以全屏滑動(dòng)了
          ((ViewGroup) rootView).addView(dragView);
          setVisibility(INVISIBLE);
        }
      }
      break;
    case MotionEvent.ACTION_MOVE:
      //請(qǐng)求父View不攔截
      getParent().requestDisallowInterceptTouchEvent(true);
      if (dragView != null) {
        //更新DragView的位置
        dragView.setDragViewLocation(mRawX, mRawY);
      }
      break;
    case MotionEvent.ACTION_UP:
      getParent().requestDisallowInterceptTouchEvent(false);
      if (dragView != null) {
        //手抬起時(shí)來判斷各種情況
        dragView.setDragUp();
      }
      break;
  }
  return true;
}

上面代碼注釋已經(jīng)很詳細(xì)了,總結(jié)一下就是通過內(nèi)部攔截法來請(qǐng)求父View是否攔截分發(fā)事件,并通過event.getRawX()和event.getRawY()來不斷更新DragView的位置,那么DragView都做了哪些事呢,接下來就看一下DragView,DragView是QQBezierView 的一個(gè)內(nèi)部View類:

 private int mState;//當(dāng)前紅點(diǎn)的狀態(tài)
 private static final int STATE_INIT = 0;//默認(rèn)靜止?fàn)顟B(tài)
 private static final int STATE_DRAG = 1;//拖拽狀態(tài)
 private static final int STATE_MOVE = 2;//移動(dòng)狀態(tài)
 private static final int STATE_DISMISS = 3;//消失狀態(tài)

首先聲明了小紅點(diǎn)的四種狀態(tài),靜止?fàn)顟B(tài),拖拽狀態(tài),移動(dòng)狀態(tài)和消失狀態(tài)。

在QQBezierView 的onTouchEvent的DOWN事件中調(diào)用了setStickyPoint()方法:

/**
 * 設(shè)置固定圓的圓心和半徑
 * @param stickyX 固定圓的X坐標(biāo)
 * @param stickyY 固定圓的Y坐標(biāo)
 */
 public void setStickyPoint(float stickyX, float stickyY, float touchX, float touchY) {
   //分別設(shè)置固定圓和拖拽圓的坐標(biāo)
   stickyPointF.set(stickyX, stickyY);
   dragPointF.set(touchX, touchY);
   //通過兩個(gè)圓點(diǎn)算出圓心距,也是拖拽的距離
   dragDistance = MathUtil.getTwoPointDistance(dragPointF, stickyPointF);
   if (dragDistance <= maxDistance) {
     //如果拖拽距離小于規(guī)定最大距離,則固定的圓應(yīng)該越來越小,這樣看著才符合實(shí)際
     stickRadius = (int) (defaultRadius - dragDistance / 10) < 10 ? 10 : (int) (defaultRadius - dragDistance / 10);
     mState = STATE_DRAG;
   } else {
     mState = STATE_INIT;
   }
 }

接著,在QQBezierView 的onTouchEvent的MOVE事件中調(diào)用了setDragViewLocation()方法:

 /**
 * 設(shè)置拖拽的坐標(biāo)位置
 *
 * @param touchX 拖拽時(shí)的X坐標(biāo)
 * @param touchY 拖拽時(shí)的Y坐標(biāo)
 */
 public void setDragViewLocation(float touchX, float touchY) {
   dragPointF.set(touchX, touchY);
   //隨時(shí)更改圓心距
   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事件中調(diào)用了setDragUp()方法:

public void setDragUp() {
  if (mState == STATE_DRAG && isInsideRange()) {
    //拖拽狀態(tài)且在范圍之內(nèi)
    startResetAnimator();
   } else if (mState == STATE_MOVE) {
     if (isInsideRange()) {
      //在范圍之內(nèi) 需要RESET
      startResetAnimator();
    } else {
      //在范圍之外 消失動(dòng)畫
      mState = STATE_DISMISS;
      startExplodeAnim();
    }
  }
}

最后來看下DragView的onDraw方法,拖拽時(shí)的貝塞爾曲線以及拖拽滑動(dòng)時(shí)的狀態(tài)都是通過onDraw實(shí)現(xiàn)的:

@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);
     //然后通過兩個(gè)圓心和半徑、斜率來獲得外切線的切點(diǎn)
     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);
     //二階貝塞爾曲線的控制點(diǎn)取得兩圓心的中點(diǎn)
     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) {
     //繪制小紅點(diǎn)消失時(shí)的爆炸動(dòng)畫
     canvas.drawBitmap(bitmaps[explodeIndex], dragPointF.x - mWidth / 2, dragPointF.y - mHeight / 2, mPaint);
   }
 }

PS:最開始使用的是 Android:clipChildren=”false” 這個(gè)屬性,如果父View只是一個(gè)普通的ViewGroup(如LinearLayout、RelativeLayout等),此時(shí)在父View中設(shè)置android:clipChildren=”false”后,子View就可以超出自己的范圍,在ViewGroup中也可以滑動(dòng)了,此時(shí)也沒問題;但是當(dāng)是RecycleView時(shí),只要ItemView設(shè)置了background屬性,滑動(dòng)時(shí)的DragView就會(huì)顯示在background的下面了,如有知其原因的還望不吝賜教~

最后再貼下源碼下載地址:Android高仿QQ小紅點(diǎn)

以上所述是小編給大家介紹的Android高仿QQ小紅點(diǎn)功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Android利用懸浮按鈕實(shí)現(xiàn)翻頁(yè)效果

    Android利用懸浮按鈕實(shí)現(xiàn)翻頁(yè)效果

    這篇文章主要介紹了Android利用懸浮按鈕實(shí)現(xiàn)翻頁(yè)效果的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • Android?Spinner和GridView組件的使用示例

    Android?Spinner和GridView組件的使用示例

    Spinner其實(shí)是一個(gè)列表選擇框,不過Android的列表選擇框并不需要顯示下拉列表,而是相當(dāng)于彈出一個(gè)菜單供用戶選擇,GridView是一個(gè)在二維可滾動(dòng)的網(wǎng)格中展示內(nèi)容的控件。網(wǎng)格中的內(nèi)容通過使用adapter自動(dòng)插入到布局中
    2022-03-03
  • Android 10 啟動(dòng)之servicemanager源碼解析

    Android 10 啟動(dòng)之servicemanager源碼解析

    這篇文章主要為大家介紹了Android 10 啟動(dòng)之servicemanager源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Android開啟新線程播放背景音樂

    Android開啟新線程播放背景音樂

    這篇文章主要為大家詳細(xì)介紹了Android開啟新線程播放背景音樂,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • android實(shí)現(xiàn)小音頻頻繁播放

    android實(shí)現(xiàn)小音頻頻繁播放

    這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)小音頻頻繁播放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • OpenGL ES正交投影實(shí)現(xiàn)方法(三)

    OpenGL ES正交投影實(shí)現(xiàn)方法(三)

    這篇文章主要為大家詳細(xì)介紹了OpenGL ES正交投影的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android自定義密碼樣式 黑點(diǎn)轉(zhuǎn)換成特殊字符

    Android自定義密碼樣式 黑點(diǎn)轉(zhuǎn)換成特殊字符

    這篇文章主要為大家詳細(xì)介紹了Android自定義密碼樣式的制作方法,黑點(diǎn)換成¥、%等特殊字符,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 谷歌被屏蔽后如何搭建安卓環(huán)境

    谷歌被屏蔽后如何搭建安卓環(huán)境

    從5月27日開始,谷歌(Google)在華的幾乎所有的服務(wù)都處于無法使用的狀態(tài),除了搜索引擎遭到屏蔽之外,谷歌的郵箱(Gmail)、日歷(Calendar)、翻譯(Translate)、地圖(Maps)、分析(Analytics)和Google AdSense等產(chǎn)品也受到了影響。同時(shí)安裝安卓環(huán)境的時(shí)候同樣容易出現(xiàn)問題
    2014-06-06
  • Android 仿余額寶數(shù)字跳動(dòng)動(dòng)畫效果完整代碼

    Android 仿余額寶數(shù)字跳動(dòng)動(dòng)畫效果完整代碼

    這篇文章主要介紹了Android 仿余額寶數(shù)字跳動(dòng)動(dòng)畫效果完整代碼,需要的朋友可以參考下
    2017-11-11
  • Android viewpager中動(dòng)態(tài)添加view并實(shí)現(xiàn)偽無限循環(huán)的方法

    Android viewpager中動(dòng)態(tài)添加view并實(shí)現(xiàn)偽無限循環(huán)的方法

    這篇文章主要介紹了Android viewpager中動(dòng)態(tài)添加view并實(shí)現(xiàn)偽無限循環(huán)的方法,涉及Android使用viewpager動(dòng)態(tài)加載view及view無限循環(huán)顯示的相關(guān)技巧,需要的朋友可以參考下
    2016-01-01

最新評(píng)論