????????轉眼已經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));??
} ??
}??