Android自定義View學習總結

????????轉眼已經18年底了,在Androd這行已經混了3年,一直說寫些東西,總是沒有執行。有想法的時候沒時間,有時間的時候沒想法,今天終于開始寫一些東西了。

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

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

?1、onMeasure 方法

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

? 1.1、當父View的specMode為EXACTLY的時候:父View強加給子View一個確切的大小,有如下兩種情況

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

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

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

? 1.2、當父view的specMode為AT_MOST的時候:父View強加給一個最大的size給子view,最大的size也就是父view的size

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

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

? 1.3、當父view的specMode為UNSPECIFIED的時候:

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

?????? 1.3.2) 此時reusltSize = 0

2、onDraw方法

2.1、畫筆

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

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

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

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

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

????//注意:冒多出來的那塊區域就是線帽!就相當于給原來的直線加上一個帽子一樣,所以叫線帽?

????setStrokeCap(Paint.Cap cap)

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

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

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

????setStrokeMiter(float miter)?

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

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

9、//獲取與設置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、//獲取與設置是否使用抗鋸齒功能,會消耗較大資源,繪制圖形速度會變慢,一般會開啟。設置后會平滑一些;

????void setAntiAlias(boolean aa)?

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

????final boolean isDither()

? ? void setDither(boolean dither)?

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

13、CornerPathEffect //圓形拐角效果

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

15、DashPathEffect //虛線效果

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

????setXfermode(Xfermode xfermode)

17、//設置MaskFilter,可以用不同的MaskFilter實現濾鏡的效果,如濾化,立體等

????setMaskFilter(MaskFilter maskfilter)

18、//設置顏色過濾器,可以在繪制顏色時實現不用顏色的變換效果

????setColorFilter(ColorFilter colorfilter)

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

????setShader(Shader shader)

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

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

21、//設置畫筆樣式1.

????Paint.Style.FILL :填充內部

????Paint.Style.FILL_AND_STROKE:填充內部和描邊

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

2.2、畫圓

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

mPaint.setColor(Color.WHITE);

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

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),又稱貝茲曲線或貝濟埃曲線,是應用于二維圖形應用程序的數學曲線。一般的矢量圖形軟件通過它來精確畫出曲線,貝茲曲線由線段節點組成,節點是可拖動的支點,線段像可伸縮的皮筋,我們在繪圖工具上看到的鋼筆工具就是來做這種矢量曲線的。主要結構:起始點、終止點(也稱錨點)、控制點。通過調整控制點,貝塞爾曲線的形狀會發生變化。

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

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

??? 公式:

??? 原理:

??? 由?P0?至?P1?的連續點,?描述的一條線段

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

??? 公式:

??? 原理:

??? 由?P0?至?P1?的連續點?Q0,描述一條線段。

????由?P1?至?P2?的連續點?Q1,描述一條線段。

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

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

??? 公式:

??? 原理:

?? 2.5.3、貝塞爾曲線的代碼實現

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

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

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

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

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

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

?? 2.5.4、貝塞爾曲線的應用

??? 2.5.4.1、波浪紋

??? 要實現一個波浪不斷涌動的效果,這種效果在很多手機應用中可見,例如手機電量,內存剩余等。類似這種需要實現波浪的效果,我們需要繪制帶有平滑自然效果的曲線,這時候就需要貝塞爾曲線來輔助了。

??? 原理圖:

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

????這樣,通過循環不斷的動畫效果,我們就實現了波浪的效果。

??? 2.5.4.2、粘連體

??? 利用二階貝塞爾曲線還可以實現,類似兩種物體粘合在一起的效果,比如我們常用的qq,在qq聊天列表上有一個非常有意思的功能,就是當我們用手指移動聊天列表上的未讀消息標志的時候,它與聊天列表會產生粘連的效果:

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

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

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

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

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

??? 2.5.4.3、彈性球

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

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

??? 接下來我們觀察彈性球的運動,大概可以分為以下幾個階段:

1)開始啟動,此時右邊點位移,其他點不動

2)開始加速

3)減速

4)到達終點

5)回彈效果

上面完成了一個彈性球的封裝,可以實現四個方向的運動,然后我們實現一個彈性球的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?{??

/**?

?*?向上運動?

?*/??

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

?/**?

?*?向下運動?

? */??

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

?/**?

*?向左運動?

? */??

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

?/**?

?*?向右運動?

? */??

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

?/**?

?*?運動方向?

?*/??

private?int?mDirection;??

/**?

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

?*/??

private?float?mAnimPercent;??

?/**?

?*?彈性距離?

?*/??

private?float?mElasticDistance;??

?/**?

*?彈性比例?

*/??

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

?/**?

*?位移距離?

*/??

private?float?mMoveDistance;??

/**?

*?動畫消費時間?

?*/??

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


?/**?

*?偏移值?

*/??

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

/**?

*?圓形偏移比例?

*/??

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


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

?/**?

*?動畫開始點?

*/??

private?Ball?mStartPoint;??


/**?

*?動畫結束點?

*/??

private?Ball?mEndPoint;??


?/**?

?*?構造方法?

?*?

*?@param?x?圓心橫坐標?

*?@param?y?圓心縱坐標?

*?@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; ?

/**?

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

?*?@param?elasticPercent?

?*/??

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

?this. mElasticPercent=?elasticPercent;?

?}??

?/**?

*?對外公布方法,設置動畫時間?

*?@param?duration?

?*/??

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

?this.mDuration?=?duration;??

?}??


/**?

?*?對外公布方法,?開啟動畫?

*?@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;??

?}??

? } ?

/**

?*?動畫狀態0?(初始狀態:圓形)?

?*/??

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

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

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

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

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

?}??

?private?Ball?mStatusPoint1; ?

/**?

*?動畫狀態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; ?

?/**?

?*?動畫狀態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; ??

?/**?

?*?動畫狀態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; ? ? ?

? /**?

? *?動畫狀態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); ?

?//再做一次賦值,防止和終點不重合??

?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);??

? ?//再做一次賦值,防止和終點不重合??

? ? ? ? ? ?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);??

? ? ? ? ? ? //再做一次賦值,防止和終點不重合??

? ? ? ? ? ?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);??

? ? ? ? ? ? //再做一次賦值,防止和終點不重合??

? ? ? ? ? ? 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;??


? ?/**?

? ? *?動畫狀態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);??

? }??


? ? /**?

? ? ?*?繪制彈性圓?

? ? *?通過繪制四段三階貝塞爾曲線,來實現有彈性變化的圓?

? ? ?*?@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??

?)?{??

? /**?

?*?繪制每一段三階貝塞爾曲線需要兩個控制點?

? */??

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;??

} ?

? /**?

?*?求兩點之間的距離?

?*?@param?x1?第一個點的橫坐標?

?*?@param?y1?第一個點的縱坐標?

*?@param?x2?第二個點的橫坐標?

*?@param?y2?第二個點的縱坐標?

*?@return?兩點距離?

*/??

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

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

} ??

}??

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • 今天女兒學校要表演,早上七點的時候趕緊往回家趕了。七點半匆匆忙忙吃了腸粉就送她去了。 中午表演完因為寶爸下午要上班...
    Ada左岸閱讀 157評論 0 0
  • 我平時叫在嘴上最多的是爸,手機聯系人上標著老爸,微信里備注了芭比,寫到這時更愿意在心底稱呼父親,這么多的稱呼...
    梨花心事閱讀 320評論 0 3
  • 這幾天有意疏遠哥哥。今天早上道早安時,哥哥用力的看著我的眼睛,我還是躲開了。后來他外出辦公,嘟了一下我的腰。前天還...
    哈姆Y特公主閱讀 121評論 0 0
  • 初次接觸到這個題目時,是在基礎寫作課上,老師給我們推薦了這位天才作家的散文,至今想不起來推薦理由,滿腦子想的是一位...
    真射手偽文藝閱讀 2,089評論 0 2