Android自定義View學(xué)習(xí)總結(jié)

????????轉(zhuǎn)眼已經(jīng)18年底了,在Androd這行已經(jīng)混了3年,一直說寫些東西,總是沒有執(zhí)行。有想法的時(shí)候沒時(shí)間,有時(shí)間的時(shí)候沒想法,今天終于開始寫一些東西了。

? ????? 回首Androd,自定義View是使用最多的,也是我第一次有計(jì)劃的去學(xué)習(xí)和整理的模塊。以下是我總結(jié)的自定義View的一些用法,沒有涉及底層原理。

一:自定義View需要重新的2個(gè)方法。

?1、onMeasure 方法

? ? ? ? 通過onMeasure方法可以得到父類的specMode和size

? 1.1、當(dāng)父View的specMode為EXACTLY的時(shí)候:父View強(qiáng)加給子View一個(gè)確切的大小,有如下兩種情況

?????? 1.1.1) 子View的layout_width或者layout_height設(shè)置為MATCH_PARENT的時(shí)候,子View的specMode為EXACTLY

?????? 1.1.2) 子View的layout_width或者layout_height設(shè)置為WRAP_CONTENT的時(shí)候,子View的specMode為AT_MOST

?????? 1.1.3) 不論子view為match_parent或者wrap_content,resultSize都等于父類的size.

? 1.2、當(dāng)父view的specMode為AT_MOST的時(shí)候:父View強(qiáng)加給一個(gè)最大的size給子view,最大的size也就是父view的size

?????? 1.2.1) 此時(shí)不論子view的為match_parent或者wrap_content,子view的specMode都為AT_MOST

?????? 1.2.2) resultSize的大小被設(shè)置為父view的大小

? 1.3、當(dāng)父view的specMode為UNSPECIFIED的時(shí)候:

?????? 1.3.1) 此時(shí)不論子view的為match_parent或者wrap_content,子view的specMode都為UNSPECIFIED

?????? 1.3.2) 此時(shí)reusltSize = 0

2、onDraw方法

2.1、畫筆

mPaint = new Paint(); //初始化

1、mPaint.setAntiAlias(true);//去除邊緣鋸齒,優(yōu)化繪制效果

2、mPaint.setColor(Color.BLACK);//設(shè)置顏色

3、setStrokeWidth(float width)?//設(shè)置畫筆寬度?

4、//設(shè)置線冒樣式,取值有Cap.ROUND(圓形線冒)、Cap.SQUARE(方形線冒)、Cap.BUTT(無線冒)?

????//注意:冒多出來的那塊區(qū)域就是線帽!就相當(dāng)于給原來的直線加上一個(gè)帽子一樣,所以叫線帽?

????setStrokeCap(Paint.Cap cap)

5、//設(shè)置線段連接處樣式,取值有:Join.MITER(結(jié)合處為銳角)、Join.Round(結(jié)合處為圓弧)、Join.BEVEL(結(jié)合處為直線)?

????setStrokeJoin(Paint.Join join)?

6、//設(shè)置筆畫的傾斜度,90度拿畫筆與30拿畫筆,畫出來的線條樣式肯定是不一樣的吧。

????setStrokeMiter(float miter)?

7、void reset() //清空畫筆復(fù)位。

8、void set(Paint src)?//設(shè)置一個(gè)外來Paint畫筆

9、//獲取與設(shè)置alpha值、顏色、ARGB等。

????void setARGB(int a, int r, int g, int b)

????int getAlpha()

????void setAlpha(int a)

????int getColor()

????void setColor(int color)

10、//獲取與設(shè)置是否使用抗鋸齒功能,會(huì)消耗較大資源,繪制圖形速度會(huì)變慢,一般會(huì)開啟。設(shè)置后會(huì)平滑一些;

????void setAntiAlias(boolean aa)?

11、//獲取與設(shè)定是否使用圖像抖動(dòng)處理,會(huì)使繪制出來的圖片顏色更加平滑和飽滿、圖像更加清晰。

????final boolean isDither()

? ? void setDither(boolean dither)?

12、setPathEffect(PathEffect effect) //設(shè)置繪制路徑的效果

13、CornerPathEffect //圓形拐角效果

14、paint.setPathEffect(newCornerPathEffect(100));//利用半徑R=50的圓來代替原來兩條直線間的夾角

15、DashPathEffect //虛線效果

16、//設(shè)置圖形重疊時(shí)的處理方式,如合并,取交集或并集,經(jīng)常用來制作橡皮的擦除效果

????setXfermode(Xfermode xfermode)

17、//設(shè)置MaskFilter,可以用不同的MaskFilter實(shí)現(xiàn)濾鏡的效果,如濾化,立體等

????setMaskFilter(MaskFilter maskfilter)

18、//設(shè)置顏色過濾器,可以在繪制顏色時(shí)實(shí)現(xiàn)不用顏色的變換效果

????setColorFilter(ColorFilter colorfilter)

19、//設(shè)置圖像效果,使用Shader可以繪制出各種漸變效果

????setShader(Shader shader)

20、//在圖形下面設(shè)置陰影層,產(chǎn)生陰影效果,radius為陰影的角度,dx和dy為陰影在x軸和y軸上的距離,color為陰影的顏色

????setShadowLayer(float radius ,float dx,floatdy,int color)

21、//設(shè)置畫筆樣式1.

????Paint.Style.FILL :填充內(nèi)部

????Paint.Style.FILL_AND_STROKE:填充內(nèi)部和描邊

????Paint.Style.STROKE :僅描邊、

2.2、畫圓

1. canvas.drawCircle(cx, cy, radius,;//外圓

mPaint.setColor(Color.WHITE);

canvas.drawCircle(cx, cy, radius - mBorderWidth, mPaint);//內(nèi)圓

2.3、繪畫弧形圓

//畫上面黑色半圓

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor(Color.BLACK);

RectF blackHalfRect = new RectF(cx - 45, cy - 90, cx + 45, cy);

canvas.drawArc(blackHalfRect, 270, 180, true, mPaint);

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor(Color.WHITE);

RectF whiteHalfRect = new RectF(cx - 45, cy, cx + 45, cy + 90);

canvas.drawArc(whiteHalfRect, 270, -180, true, mPaint);

?? 2.4、繪畫半圓

RectF mRectf = new RectF(left, top, right,botton);

mPaint.setColor(Color.WHITE);

canvas.drawArc(mRectf, 270, 180, true, mPaint);

mPaint.setColor(Color.BLACK);

canvas.drawArc(mRectf, 270, -180, true, mPaint);

?? 2.5、貝塞爾曲線

??? 2.5.1、什么是貝塞爾曲線

??? 貝塞爾曲線(Bézier?curve),又稱貝茲曲線或貝濟(jì)埃曲線,是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段節(jié)點(diǎn)組成,節(jié)點(diǎn)是可拖動(dòng)的支點(diǎn),線段像可伸縮的皮筋,我們?cè)诶L圖工具上看到的鋼筆工具就是來做這種矢量曲線的。主要結(jié)構(gòu):起始點(diǎn)、終止點(diǎn)(也稱錨點(diǎn))、控制點(diǎn)。通過調(diào)整控制點(diǎn),貝塞爾曲線的形狀會(huì)發(fā)生變化。

??? 2.5.2、貝塞爾曲線的分類

??? 2.5.2.1、一階貝塞爾曲線(線段):

??? 公式:

??? 原理:

??? 由?P0?至?P1?的連續(xù)點(diǎn),?描述的一條線段

??? 2.5.2.2、二階貝塞爾曲線(拋物線):

??? 公式:

??? 原理:

??? 由?P0?至?P1?的連續(xù)點(diǎn)?Q0,描述一條線段。

????由?P1?至?P2?的連續(xù)點(diǎn)?Q1,描述一條線段。

????由?Q0?至?Q1?的連續(xù)點(diǎn)?B(t),描述一條二次貝塞爾曲線。

??? 2.5.2.3、三階貝塞爾曲線:

??? 公式:

??? 原理:

?? 2.5.3、貝塞爾曲線的代碼實(shí)現(xiàn)

?? quadTo()方法從上一個(gè)點(diǎn)為起點(diǎn)開始繪制貝塞爾曲線,其中(x1,y1)為輔 助控制點(diǎn),(x2,y2)為終點(diǎn)。

??? Path?mPath?=?new?Path();

??? mPath.moveTo(x0,y0);

??? mPath.quadTo(x1,y1,x2,y2);

? ? 如調(diào)用以上代碼,即繪制起點(diǎn)(x0,y0),終點(diǎn)(x2,y2),輔助控制點(diǎn)(x1,y1)的貝塞爾曲線。因此,通過不斷改變這三個(gè)點(diǎn)的位置,我們可以繪制出各種各樣的曲線。

???? cubicTo()方法從上一個(gè)點(diǎn)為起點(diǎn)開始繪制三階貝塞爾曲線,其中(x1,y1),(?x2,?y2?)為輔助控制點(diǎn),(x3,y3)為終點(diǎn)。

?? 2.5.4、貝塞爾曲線的應(yīng)用

??? 2.5.4.1、波浪紋

??? 要實(shí)現(xiàn)一個(gè)波浪不斷涌動(dòng)的效果,這種效果在很多手機(jī)應(yīng)用中可見,例如手機(jī)電量,內(nèi)存剩余等。類似這種需要實(shí)現(xiàn)波浪的效果,我們需要繪制帶有平滑自然效果的曲線,這時(shí)候就需要貝塞爾曲線來輔助了。

??? 原理圖:

???????? 圖中的矩陣即為視圖的可見范圍,也就是我們手機(jī)常見的區(qū)域。通過屬性動(dòng)畫類ValueAnimator不斷改變點(diǎn)1的橫坐標(biāo),隨著點(diǎn)1橫坐標(biāo)向右移動(dòng),點(diǎn)2,點(diǎn)3,點(diǎn)4,點(diǎn)5,以及四個(gè)控制點(diǎn)的坐標(biāo)隨著點(diǎn)1的移動(dòng)同時(shí)位移相同距離,每一次坐標(biāo)點(diǎn)更新,我們調(diào)用一次invalidate()方法,調(diào)用draw重新繪制視圖,繪制四段貝塞爾曲線。最后點(diǎn)1移動(dòng)到原先點(diǎn)3的位置,這樣就完成了一次動(dòng)畫。

????這樣,通過循環(huán)不斷的動(dòng)畫效果,我們就實(shí)現(xiàn)了波浪的效果。

??? 2.5.4.2、粘連體

??? 利用二階貝塞爾曲線還可以實(shí)現(xiàn),類似兩種物體粘合在一起的效果,比如我們常用的qq,在qq聊天列表上有一個(gè)非常有意思的功能,就是當(dāng)我們用手指移動(dòng)聊天列表上的未讀消息標(biāo)志的時(shí)候,它與聊天列表會(huì)產(chǎn)生粘連的效果:

????現(xiàn)在,我們來模擬這種效果,利用學(xué)到的二階貝塞爾曲線來繪制。

??? 我們看到原理圖,基本構(gòu)造為兩個(gè)圓,和兩端貝塞爾曲線,繪制貝塞爾曲線,由于這是一個(gè)二階的貝塞爾曲線,我們只需要一個(gè)控制點(diǎn),在這個(gè)圖里,我們的兩條貝塞爾曲線的兩個(gè)控制點(diǎn)分別為(x1,y1)(x4,?y4)的中點(diǎn),(x2,?y2)(x3,?y3)的中點(diǎn)。

??? 從圖中可以看出,我們的貝塞爾曲線由我們的控制點(diǎn)控制,控制點(diǎn)又是被起點(diǎn)和終點(diǎn)控制著,因此,當(dāng)兩個(gè)圓距離越大,曲線越趨于平緩,當(dāng)兩個(gè)圓距離越小,曲線的波動(dòng)度越大,這樣,我們想要的粘連的效果就實(shí)現(xiàn)了。另外,這里有一個(gè)還有角度(圖中的45度角)可以用來控制,也可以作為控制曲線波動(dòng)度的參數(shù)。

??? 通過以上分析,我們通過一個(gè)方法來繪制兩個(gè)圓之間的粘連體路徑:

??? 我們給控件設(shè)置一個(gè)粘連的最大距離,即如果兩個(gè)圓之間的距離超過這個(gè)值,則不再繪制粘連體。

??? 2.5.4.3、彈性球

??? 三階貝塞爾曲線,就是有兩個(gè)控制點(diǎn),它相比二階曲線的優(yōu)點(diǎn)是,由于控制點(diǎn)的增加,它能夠更加輕松地繪制出更平滑更自然的曲線。

??? 如何繪制類似這種,看起來具有彈性球的滑動(dòng)球,我們需要使用三階貝塞爾曲線,那么首先如何用三階貝塞爾曲線繪制出一個(gè)圓,這里有一篇文章,是關(guān)于如何用貝塞爾曲線繪制圓:http://spencermortensen.com/articles/bezier-circle/?,大概意思是講,我們需要一個(gè)值就是c?=?0.552284749,如下圖,要繪制右上角的圓弧,我們需要兩個(gè)控制點(diǎn),其中B就是一個(gè)控制點(diǎn),我們需要保證AB?=?c?*r,即可以畫出1/4的圓弧,以此類推,連續(xù)畫四段這樣的圓弧,就可以畫出一個(gè)標(biāo)準(zhǔn)的圓。

??? 接下來我們觀察彈性球的運(yùn)動(dòng),大概可以分為以下幾個(gè)階段:

1)開始啟動(dòng),此時(shí)右邊點(diǎn)位移,其他點(diǎn)不動(dòng)

2)開始加速

3)減速

4)到達(dá)終點(diǎn)

5)回彈效果

上面完成了一個(gè)彈性球的封裝,可以實(shí)現(xiàn)四個(gè)方向的運(yùn)動(dòng),然后我們實(shí)現(xiàn)一個(gè)彈性球的loader

package?com.zero.bezier.widget.elastic;


import?android.animation.Animator;??

import?android.animation.ValueAnimator;??

import?android.graphics.Path;??

import?android.graphics.PointF;??

import?android.view.animation.AccelerateDecelerateInterpolator; ?

/**?

*?彈性球?

*?@author?linzewu?

*?@date?2016/6/1?

*/??

public?class?ElasticBall?extends?Ball?{??

/**?

?*?向上運(yùn)動(dòng)?

?*/??

private?static?final?int?DIRECTION_UP?=?1;??

?/**?

?*?向下運(yùn)動(dòng)?

? */??

private?static?final?int?DIRECTION_DOWN?=?2;??

?/**?

*?向左運(yùn)動(dòng)?

? */??

private?static?final?int?DIRECTION_LEFT?=?3;??

?/**?

?*?向右運(yùn)動(dòng)?

? */??

private?static?final?int?DIRECTION_RIGHT?=?4;??

?/**?

?*?運(yùn)動(dòng)方向?

?*/??

private?int?mDirection;??

/**?

*?動(dòng)畫完成百分比(0~1)?

?*/??

private?float?mAnimPercent;??

?/**?

?*?彈性距離?

?*/??

private?float?mElasticDistance;??

?/**?

*?彈性比例?

*/??

private?float?mElasticPercent?=?0.8f;??

?/**?

*?位移距離?

*/??

private?float?mMoveDistance;??

/**?

*?動(dòng)畫消費(fèi)時(shí)間?

?*/??

private?long?mDuration?=?1500;??


?/**?

*?偏移值?

*/??

private?float?offsetTop,?offsetBottom,?offsetLeft,?offsetRight;??

/**?

*?圓形偏移比例?

*/??

private?float?c?=?0.551915024494f;??


private?float?c2?=?0.65f;??

?/**?

*?動(dòng)畫開始點(diǎn)?

*/??

private?Ball?mStartPoint;??


/**?

*?動(dòng)畫結(jié)束點(diǎn)?

*/??

private?Ball?mEndPoint;??


?/**?

?*?構(gòu)造方法?

?*?

*?@param?x?圓心橫坐標(biāo)?

*?@param?y?圓心縱坐標(biāo)?

*?@param?radius?圓半徑?

*/??

public?ElasticBall(float?x,?float?y,?float?radius)?{??

super(x,?y,?radius);??

init();??

?}??


private?void?init()?{??

mElasticDistance?=?mElasticPercent?*?radius;??

offsetTop?=?c?*?radius;??

offsetBottom?=?c?*?radius;??

offsetLeft?=?c?*?radius;??

offsetRight?=?c?*?radius;??

}??


public?interface?ElasticBallInterface{??

void?onChange(Path?path);??

void?onFinish();??

} ?

private?ElasticBallInterface?mElasticBallInterface; ?

/**?

*?對(duì)外公布方法,設(shè)置彈性比例?(0~1)?

?*?@param?elasticPercent?

?*/??

?public?void?setElasticPercent(float?elasticPercent)?{??

?this. mElasticPercent=?elasticPercent;?

?}??

?/**?

*?對(duì)外公布方法,設(shè)置動(dòng)畫時(shí)間?

*?@param?duration?

?*/??

public?void?setDuration(long?duration)?{??

?this.mDuration?=?duration;??

?}??


/**?

?*?對(duì)外公布方法,?開啟動(dòng)畫?

*?@param?endPoint?

*/??

public?void?startElasticAnim(PointF?endPoint,?ElasticBallInterface?elasticBallInterface)?{??

this.mEndPoint?=?new?ElasticBall(endPoint.x,?endPoint.y,?radius);??

this.mStartPoint?=?new?ElasticBall(x,?y,?radius);??

this.mStatusPoint1?=?new?ElasticBall(x,?y,?radius);??

this.mStatusPoint2?=?new?ElasticBall(x,?y,?radius);??

this.mStatusPoint3?=?new?ElasticBall(x,?y,?radius);??

this.mStatusPoint4?=?new?ElasticBall(x,?y,?radius);??

this.mStatusPoint5?=?new?ElasticBall(x,?y,?radius);??

this.mElasticBallInterface?=?elasticBallInterface;??

judgeDirection();??

mMoveDistance?=?getDistance(mStartPoint.x,?mStatusPoint1.y,?endPoint.x,?endPoint.y);??

animStatus0();??

ValueAnimator?valueAnimator?=?ValueAnimator.ofFloat(0,?1); ?

valueAnimator.setDuration(mDuration); ?

valueAnimator.setInterpolator(new?AccelerateDecelerateInterpolator());??

valueAnimator.start();??

valueAnimator.addUpdateListener(new?ValueAnimator.AnimatorUpdateListener()?{??

@Override??

public?void?onAnimationUpdate(ValueAnimator?animation)?{??

mAnimPercent?=?(float)?animation.getAnimatedValue();??

if(mAnimPercent>=0?&&?mAnimPercent?<=?0.2){??

animStatus1();??

?} ?else?if(mAnimPercent?>?0.2?&&?mAnimPercent?<=?0.5){ ?

animStatus2();??

?} ?else?if(mAnimPercent?>?0.5?&&?mAnimPercent?<=?0.8){ ?

?animStatus3();??

?} ?else?if(mAnimPercent?>?0.8?&&?mAnimPercent?<=?0.9){ ?

animStatus4();??

?} ??else?if(mAnimPercent?>?0.9&&mAnimPercent?<=?1){ ?

?animStatus5();??

?}??

?if?(mElasticBallInterface?!=?null)?{??

?mElasticBallInterface.onChange(drawElasticCircle(topX,?topY,?offsetTop,?offsetTop,??

?bottomX,?bottomY,?offsetBottom,?offsetBottom,??

leftX,?leftY,?offsetLeft,?offsetLeft,??

?rightX,?rightY,?offsetRight,?offsetRight));??

?}??

}??

?});??

?valueAnimator.addListener(new?Animator.AnimatorListener()?{??

@Override??

public?void?onAnimationStart(Animator?animation)?{??


?} ?

@Override??

?public?void?onAnimationEnd(Animator?animation)?{??

if?(mElasticBallInterface?!=?null)?{??

mElasticBallInterface.onFinish();??

?}??

} ?

@Override??

public?void?onAnimationCancel(Animator?animation)?{ ?

? } ?

@Override??

?public?void?onAnimationRepeat(Animator?animation)?{ ?

}??

?});??

} ?

?private?void?judgeDirection()?{??

if?(mEndPoint.x?-?mStartPoint.x?>?0)?{??

mDirection?=?DIRECTION_RIGHT;??

}else?if?(mEndPoint.x?-?mStartPoint.x?<?0)?{??

mDirection?=?DIRECTION_LEFT;??

}else?if?(mEndPoint.y?-?mStartPoint.x?>?0)?{??

?mDirection?=?DIRECTION_DOWN;??

?}else?if?(mEndPoint.y?-?mStartPoint.y?<?0){??

mDirection?=?DIRECTION_UP;??

?}??

? } ?

/**

?*?動(dòng)畫狀態(tài)0?(初始狀態(tài):圓形)?

?*/??

?private?void?animStatus0()?{??

offsetTop?=?c?*?radius;??

offsetBottom?=?c?*?radius;??

offsetLeft?=?c?*?radius;??

offsetRight?=?c?*?radius;??

?}??

?private?Ball?mStatusPoint1; ?

/**?

*?動(dòng)畫狀態(tài)1?(0~0.2)?

?*/??

private?void?animStatus1()?{??

?float?percent?=?mAnimPercent?*?5f;??

if?(mDirection?==?DIRECTION_LEFT)?{??

?leftX?=?mStartPoint.leftX?-?percent?*?mElasticDistance;??

}?else?if?(mDirection?==?DIRECTION_RIGHT)?{??

rightX?=?mStartPoint.rightX?+?percent?*?mElasticDistance;??

?}?else?if?(mDirection?==?DIRECTION_UP)?{??

?topY?=?mStartPoint.topY?-?percent?*?mElasticDistance;??

?}?else?if?(mDirection?==?DIRECTION_DOWN)?{??

? bottomY?=?mStartPoint.bottomY?+?percent?*?mElasticDistance;??

?}??

?mStatusPoint1.refresh(x,?y,?topX,?topY,?bottomX,?bottomY,??

? leftX,?leftY,?rightX,?rightY);??

? }??

private?Ball?mStatusPoint2; ?

?/**?

?*?動(dòng)畫狀態(tài)2?(0.2~0.5)?

? */??

?private?void?animStatus2()?{??

?float?percent?=?(float)?((mAnimPercent?-?0.2)?*?(10f?/?3));??

?if?(mDirection?==?DIRECTION_LEFT)?{??

?leftX?=?mStatusPoint1.leftX?-?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?x?=?mStatusPoint1.x?-?percent?*?(mMoveDistance?/?2);??

rightX?=?mStatusPoint1.rightX?-?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?topX?=?x;??

?bottomX?=?x;??

//偏移值稍作變化??

?offsetTop?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

offsetBottom?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

}?else?if?(mDirection?==?DIRECTION_RIGHT)?{??

?rightX?=?mStatusPoint1.rightX?+?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?x?=?mStatusPoint1.x?+?percent?*?(mMoveDistance?/?2);??

leftX?=?mStatusPoint1.leftX?+?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?topX?=?x;??

?bottomX?=?x;??

//偏移值稍作變化??

?offsetTop?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

offsetBottom?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

}?else?if?(mDirection?==?DIRECTION_UP)?{??

?topY?=?mStatusPoint1.topY?-?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

y?=?mStatusPoint1.y?-?percent?*?(mMoveDistance?/?2);??

bottomY?=?mStatusPoint1.bottomY?-?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?leftY?=?y;??

?rightY?=?y;??

?//偏移值稍作變化??

offsetLeft?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

offsetRight?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

}?else?if?(mDirection?==?DIRECTION_DOWN)?{??

bottomY?=?mStatusPoint1.bottomY?+?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?y?=?mStatusPoint1.y?+?percent?*?(mMoveDistance?/?2);??

?topY?=?mStatusPoint1.topY?+?percent?*?(mMoveDistance?/?2?-?mElasticDistance?/?2?);??

?leftY?=?y;??

rightY?=?y;??

?//偏移值稍作變化??

offsetLeft?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

?offsetRight?=?radius?*?c?+?radius?*?(?c2?-?c?)?*?percent;??

? }??

?mStatusPoint2.refresh(x,?y,?topX,?topY,?bottomX,?bottomY,??

?leftX,?leftY,?rightX,?rightY);??

?} ?

private?Ball?mStatusPoint3; ??

?/**?

?*?動(dòng)畫狀態(tài)3?(0.5~0.8)?

? */??

private?void?animStatus3()?{??

float?percent?=?(mAnimPercent?-?0.5f)?*?(10f?/?3f);??

?if?(mDirection?==?DIRECTION_LEFT)?{??

? leftX?=?mStatusPoint2.leftX?-?Math.abs(percent?*?(mEndPoint.rightX?-?mStatusPoint2.rightX)); ?

x?=?mStatusPoint2.x?-?Math.abs(percent?*?(mEndPoint.x?-?mStatusPoint2.x));??

?rightX?=?mStatusPoint2.rightX?-?Math.abs(percent?*?(mEndPoint.x?-?mStatusPoint2.x));??

?topX?=?x;??

?bottomX?=?x;??

?//偏移值稍作變化??

?offsetTop?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

?offsetBottom?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

? }?else?if?(mDirection?==?DIRECTION_RIGHT)?{??

rightX?=?mStatusPoint2.rightX?+?percent?*?(mEndPoint.rightX?-?mStatusPoint2.rightX);??

?x?=?mStatusPoint2.x?+?percent?*?(mEndPoint.x?-?mStatusPoint2.x);??

? leftX?=?mStatusPoint2.leftX?+?percent?*?(mEndPoint.x?-?mStatusPoint2.x);??

? topX?=?x;??

? bottomX?=?x;??

? ?//偏移值稍作變化??

? offsetTop?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

?offsetBottom?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

?}?else?if?(mDirection?==?DIRECTION_UP)?{??

topY?=?mStatusPoint2.topY?-?Math.abs(percent?*?(mEndPoint.topY?-?mStatusPoint2.topY)); ?

y?=?mStatusPoint2.y?-?Math.abs(percent?*?(mEndPoint.y?-?mStatusPoint2.y));??

?bottomY?=?mStatusPoint2.bottomY?-?Math.abs(percent?*?(mEndPoint.y?-?mStatusPoint2.y));??

leftY?=?y;??

?rightY?=?y;??

?//偏移值稍作變化??

offsetLeft?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

?offsetRight?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

?}?else?if?(mDirection?==?DIRECTION_DOWN)?{??

?bottomY?=?mStatusPoint2.bottomY?+?percent?*?(mEndPoint.bottomY?-?mStatusPoint2.bottomY); ?

?y?=?mStatusPoint2.y?+?percent?*?(mEndPoint.y?-?mStatusPoint2.y);??

?topY?=?mStatusPoint2.topY?+?percent?*?(mEndPoint.y?-?mStatusPoint2.y);??

leftY?=?y;??

rightY?=?y;??

//偏移值稍作變化??

?offsetLeft?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

offsetRight?=?radius?*?c2?-?radius?*?(?c2?-?c?)?*?percent;??

}??

mStatusPoint3.refresh(x,?y,?topX,?topY,?bottomX,?bottomY,??

?leftX,?leftY,?rightX,?rightY);??

?} ??

private?Ball?mStatusPoint4; ? ? ?

? /**?

? *?動(dòng)畫狀態(tài)4?(0.8~0.9)?

? */??

private?void?animStatus4()?{??

?float?percent?=?(float)?(mAnimPercent?-?0.8)?*?10;??

??if?(mDirection?==?DIRECTION_LEFT)?{??

?rightX?=?mStatusPoint3.rightX?-?percent?*?(Math.abs(mEndPoint.rightX?-?mStatusPoint3.rightX)?+?mElasticDistance/2); ?

?//再做一次賦值,防止和終點(diǎn)不重合??

?leftX?=?mEndPoint.leftX;??

x?=?mEndPoint.x;??

? bottomX?=?mEndPoint.bottomX;??

? topX?=?mEndPoint.topX;??

? }?else?if?(mDirection?==?DIRECTION_RIGHT)?{??

? leftX?=?mStatusPoint3.leftX?+?percent?*?(mEndPoint.leftX?-?mStatusPoint3.leftX?+??

? ? ?mElasticDistance/2);??

? ?//再做一次賦值,防止和終點(diǎn)不重合??

? ? ? ? ? ?rightX?=?mEndPoint.rightX;??

? ? ? ? ? ? x?=?mEndPoint.x;??

? ? ? ? ? ? bottomX?=?mEndPoint.bottomX;??

? ? ? ? ? ? topX?=?mEndPoint.topX;??

? ? ? ? }?else?if?(mDirection?==?DIRECTION_UP)?{??

? ? ? ? ? ? bottomY?=?mStatusPoint3.bottomY?-?percent?*?(Math.abs(mEndPoint.bottomY?-?mStatusPoint3??

? ? ? ? ? ? ? ? ? ?.bottomY)?+?mElasticDistance/2);??

? ? ? ? ? ? //再做一次賦值,防止和終點(diǎn)不重合??

? ? ? ? ? ?topY?=?mEndPoint.topY;??

? ? ? ? ? ?y?=?mEndPoint.y;??

? ? ? ? ? ?leftY?=?mEndPoint.leftY;??

? ? ? ? ? ?rightY?=?mEndPoint.rightY;??

? ? ? ?}?else?if?(mDirection?==?DIRECTION_DOWN)?{??

? ? ? ? ? ? topY?=?mStatusPoint3.topY?+?percent?*?(mEndPoint.topY?-?mStatusPoint3??

? ? ? ? ? ? ? ? ? ?.topY?+?mElasticDistance/2);??

? ? ? ? ? ? //再做一次賦值,防止和終點(diǎn)不重合??

? ? ? ? ? ? bottomY?=?mEndPoint.bottomY;??

? ? ? ? ? ?y?=?mEndPoint.y;??

? ? ? ? ? ?leftY?=?mEndPoint.leftY;??

? ? ? ? ? ?rightY?=?mEndPoint.rightY;??

? ? ? ? }??

? ? ? ? mStatusPoint4.refresh(x,?y,?topX,?topY,?bottomX,?bottomY,??

? ? ? ? ? ? ? ?leftX,?leftY,?rightX,?rightY);??

? ? }??


? ??private?Ball?mStatusPoint5;??


? ?/**?

? ? *?動(dòng)畫狀態(tài)5?(0.9~1)回彈?

? ? ?*/??

? ?private?void?animStatus5()?{??

? ? ? ?float?percent?=?(float)?(mAnimPercent?-?0.9)?*?10;??

? ? ? ?if?(mDirection?==?DIRECTION_LEFT)?{??

? ? ? ? ? ?rightX?=?mStatusPoint4.rightX?+?percent?*?(mEndPoint.rightX?-?mStatusPoint4.rightX);??

? ? ? ?}?else?if?(mDirection?==?DIRECTION_RIGHT)?{??

? ? ? ? ? ?leftX?=?mStatusPoint4.leftX?+?percent?*?(mEndPoint.leftX?-?mStatusPoint4.leftX);??

? ? ? ?}?else?if?(mDirection?==?DIRECTION_UP)?{??

? ? ? ? ? ?bottomY?=?mStatusPoint4.bottomY?+?percent?*?(mEndPoint.bottomY?-?mStatusPoint4.bottomY);??

? ? ? ?}?else?if?(mDirection?==?DIRECTION_DOWN)?{??

? ? ? ? ? topY?=?mStatusPoint4.topY?+?percent?*?(mEndPoint.topY?-?mStatusPoint4.topY);??

? ? ? }??

? ? ? ?mStatusPoint5.refresh(x,?y,?topX,?topY,?bottomX,?bottomY,??

? ? ? ? ? ? ? ?leftX,?leftY,?rightX,?rightY);??

? }??


? ? /**?

? ? ?*?繪制彈性圓?

? ? *?通過繪制四段三階貝塞爾曲線,來實(shí)現(xiàn)有彈性變化的圓?

? ? ?*?@param?topX?

? ? *?@param?topY?

? ?*?@param?offsetTop1?

? ?*?@param?offsetTop2?

? ? *?@param?bottomX?

? ?*?@param?bottomY?

? ?*?@param?offsetBottom1?

? ? *?@param?offsetBottom2?

? ? ?*?@param?leftX?

? ? *?@param?leftY?

? ? *?@param?offsetLeft1?

? ?*?@param?offsetLeft2?

? ? ?*?@param?rightX?

? ? ?*?@param?rightY?

? ?*?@param?offsetRight1?

? ?*?@param?offsetRight2?

? ?*?@return?

? ?*/??

? ??private?Path?drawElasticCircle(??

? ? ? ? ? ??float?topX,?float?topY,?float?offsetTop1,?float?offsetTop2,??

? ? ? ? ? ??float?bottomX,?float?bottomY,?float?offsetBottom1,?float?offsetBottom2,??

? ? ? ? ? ??float?leftX,?float?leftY,?float?offsetLeft1,?float?offsetLeft2,??

? ? ? ? ??float?rightX,?float?rightY,?float?offsetRight1,?float?offsetRight2??

?)?{??

? /**?

?*?繪制每一段三階貝塞爾曲線需要兩個(gè)控制點(diǎn)?

? */??

PointF?controlTop1,?controlTop2,?controlBottom1,?controlBottom2,??

?controlLeft1,?controlLeft2,?controlRight1,?controlRight2;??

controlTop1?=?new?PointF();??

controlTop1.x?=?topX?-?offsetTop1;??

?controlTop1.y?=?topY;??

controlTop2?=?new?PointF();??

controlTop2.x?=?topX?+?offsetTop2;??

?controlTop2.y?=?topY;??

controlBottom1?=?new?PointF();??

controlBottom1.x?=?bottomX?-?offsetBottom1;??

controlBottom1.y?=?bottomY;??

controlBottom2?=?new?PointF();??

?controlBottom2.x?=?bottomX?+?offsetBottom2;??

?controlBottom2.y?=?bottomY;??

?controlLeft1?=?new?PointF();??

controlLeft1.x?=?leftX;??

?controlLeft1.y?=?leftY?-?offsetLeft1;??

?controlLeft2?=?new?PointF();??

controlLeft2.x?=?leftX;??

?controlLeft2.y?=?leftY?+?offsetLeft2;??

controlRight1?=?new?PointF();??

controlRight1.x?=?rightX;??

?controlRight1.y?=?rightY?-?offsetRight1;??

?controlRight2?=?new?PointF();??

?controlRight2.x?=?rightX;??

?controlRight2.y?=?rightY?+?offsetRight2;??


Path?path?=?new?Path();??

?/**?

?*?繪制top到left的圓弧?

? */??

path.moveTo(topX,?topY);??

?path.cubicTo(controlTop1.x,?controlTop1.y,?controlLeft1.x,?controlLeft1.y,?leftX,?leftY);??

?/**?

*?繪制left到bottom的圓弧?

?*/??

path.cubicTo(controlLeft2.x?,controlLeft2.y,?controlBottom1.x,?controlBottom1.y,?bottomX, ?bottomY); ?

/**?

?*?繪制bottom到right的圓弧?

?*/??

? ? ? ?path.cubicTo(controlBottom2.x,?controlBottom2.y,?controlRight2.x,?controlRight2.y, ?rightX,?rightY); ?

? ? ? ?/**?

? ? ? ? *?繪制right到top的圓弧?

? ? ? ? ?*/??

? ? ? ?path.cubicTo(controlRight1.x,?controlRight1.y,?controlTop2.x,?controlTop2.y,?topX,?topY);??

return?path;??

} ?

? /**?

?*?求兩點(diǎn)之間的距離?

?*?@param?x1?第一個(gè)點(diǎn)的橫坐標(biāo)?

?*?@param?y1?第一個(gè)點(diǎn)的縱坐標(biāo)?

*?@param?x2?第二個(gè)點(diǎn)的橫坐標(biāo)?

*?@param?y2?第二個(gè)點(diǎn)的縱坐標(biāo)?

*?@return?兩點(diǎn)距離?

*/??

private?float?getDistance(float?x1,?float?y1,?float?x2,?float?y2)?{??

??return?(float)?Math.sqrt((x1?-?x2)?*?(x1?-?x2)?+?(y1?-?y2)?*?(y1?-?y2));??

} ??

}??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 今天女兒學(xué)校要表演,早上七點(diǎn)的時(shí)候趕緊往回家趕了。七點(diǎn)半匆匆忙忙吃了腸粉就送她去了。 中午表演完因?yàn)閷毎窒挛缫习?..
    Ada左岸閱讀 212評(píng)論 0 0
  • 我平時(shí)叫在嘴上最多的是爸,手機(jī)聯(lián)系人上標(biāo)著老爸,微信里備注了芭比,寫到這時(shí)更愿意在心底稱呼父親,這么多的稱呼...
    梨花心事閱讀 400評(píng)論 0 3
  • 這幾天有意疏遠(yuǎn)哥哥。今天早上道早安時(shí),哥哥用力的看著我的眼睛,我還是躲開了。后來他外出辦公,嘟了一下我的腰。前天還...
    哈姆Y特公主閱讀 144評(píng)論 0 0
  • 初次接觸到這個(gè)題目時(shí),是在基礎(chǔ)寫作課上,老師給我們推薦了這位天才作家的散文,至今想不起來推薦理由,滿腦子想的是一位...
    真射手偽文藝閱讀 2,375評(píng)論 0 2

友情鏈接更多精彩內(nèi)容