日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

android qq红点,Android高仿QQ小红点功能

發(fā)布時(shí)間:2024/9/27 Android 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android qq红点,Android高仿QQ小红点功能 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

先給大家展示下效果圖:

繪制貝塞爾曲線:

主要是當(dāng)在一定范圍內(nèi)拖拽時(shí)算出固定圓和拖拽圓的外切直線以及對應(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()獲得頂級(jí)根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:

//請求父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:

//請求父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)部攔截法來請求父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)功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

總結(jié)

以上是生活随笔為你收集整理的android qq红点,Android高仿QQ小红点功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。