其實吧這個東西我一直很想學習的,但是一直不知道,怎么開始跑代碼。
正好看到一篇很厲害的代碼原始帖子,沒有對比沒有傷害。。來讓我互相傷害吧。
先來一貼 貝塞爾曲線開發的藝術,作者是大神不介紹,這篇文章,寫的很好理解,貝塞爾曲線,我就不嘮叨了。
如果你已經看完,這個帖子那么我感覺,你絕對值得,曲線是什么了。但是代碼中用到了一個
android path rQuadTo() 這個方法,
我簡答解釋一下:
rQuadTo(float dx1, float dy1, float dx2, float dy2)
利用quadTo定義絕對坐標
quadTo 舉例
path.moveTo(300,400);
path.quadTo(500,300,500,500);
等同rQuadTo
path.moveTo(300,400);
path.rQuadTo(200,-100,200,100)
quadto 控制點是,500,300
rquadto 控制點是,300+200,400-100
這個例子是不是可以看懂了。這個才是關鍵。
我們開始擼代碼吧。
紅標文件講解 這里埋了雷,其實是脫離窗口。
main
主類中并沒有什么特別是吧,一個intent 其實是一個sever,,我們放在后面說,我們先看,這個自定義view
一般自定義view基本遵循以下這四個方法。默默記住就好了。基本是固定的【嘿哈】。一個讀代碼的方法,先debug這重點代碼,然后運行看運行邏輯。
view 自定義基本框架
1、自定義View的屬性
2、在View的構造方法中獲得我們自定義的屬性
3、重寫onMesure
4、重寫onDraw
一個手機識別類,代碼很簡單,當前類,定義一個雙擊和單擊事件。
構造方法,把上面的手勢識別,添加到,自己的view中。
public WaterProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
getAttrValue(attrs);
//初始化畫筆的相關屬性
initPaint();
mProgressPath = new Path();
mGestureDetector = new GestureDetector(context,new MyGestureDetector());
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//將觸摸事件交由mGestureDetector處理
mGestureDetector.onTouchEvent(motionEvent);
return true;
}
});
}
其實這個雙擊動畫,就是Handler 在玩,并沒有什么特別的,關鍵點是,setprogress(0) 先清空進度,看到了吧,這就是,if為什么這樣判斷了。然后每次都重新繪制,動畫就開始了。
每個自定義的view基本都會,用onDraw ,其實我感覺如果你不用onDraw其實完全可以通過基本組件組合出來。
@Override
protected synchronized void onDraw(Canvas canvas) {
float ratio = getProgress()*1.0f/getMax();
//去邊界的寬高
int width = getWidth()-getPaddingLeft()-getPaddingRight();
int height = getHeight()-getPaddingTop()-getPaddingBottom();
//畫圓
mPaintCanvas.drawCircle(width/2,height/2,height/2,mCirclePaint);
//畫進度
mProgressPath.reset();
//從右上邊開始draw path
int rightTop = (int) ((1-ratio)*height);
mProgressPath.moveTo(width,rightTop);
mProgressPath.lineTo(width,height);
mProgressPath.lineTo(0,height);
mProgressPath.lineTo(0,rightTop);
//畫貝塞爾曲線,形成波浪線 這里的波浪個數 其實這里為什么用高呢,,
//其實我想說,用寬也行,因為是個圓形,,哈哈,是不是,很逗比,
int count = (int) Math.ceil(height*1.0f/(mRippleTop *4));
//不是單擊animation狀態
if(!isSingleTapAnimation&&getProgress()>0) {
float top = (mTargetProgress-getProgress())*1.0f/mTargetProgress* mRippleTop;
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop,-top,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop,top,2* mRippleTop,0);
}
} else {
//單擊animation狀態
//mSingleTapAnimationCount 單機動畫的次數,默認是50 這里其實就是想讓動畫每次的固定搞度提升。
float top = (mSingleTapAnimationCount*1.0f/50)*10;
//奇偶數時曲線切換
if(mSingleTapAnimationCount%2==0) {
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop *2,-top*2,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop *2,top*2,2* mRippleTop,0);
}
} else {
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop *2,top*2,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop *2,-top*2,2* mRippleTop,0);
}
}
}
mProgressPath.close();
mPaintCanvas.drawPath(mProgressPath,mProgressPaint);
//畫進度文字
String text = ((int)(ratio*100))+"%";
//獲得文字的寬度
float textWidth = mTextPaint.measureText(text);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
//descent+ascent為負數,所以是減而不是加
float baseLine = height*1.0f/2 - (metrics.descent+metrics.ascent)/2;
mPaintCanvas.drawText(text,width/2-textWidth/2,baseLine,mTextPaint);
canvas.drawBitmap(mBitmap,0,0,null);
}
還有一個重點代碼,SRC_IN 給你一個連接隨便一個連接,你就可以知道他是什么了,簡答到,你喊媽媽我餓了一樣。
private void initPaint() {
mCirclePaint = new Paint();
mCirclePaint.setColor(mCircleColor);
mCirclePaint.setStyle(Paint.Style.FILL);
mCirclePaint.setAntiAlias(true);
mCirclePaint.setDither(true);
mProgressPaint = new Paint();
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setDither(true);
mProgressPaint.setStyle(Paint.Style.FILL);
//setXfermode模式 SRC_IN
mProgressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
mTextPaint = new Paint();
mTextPaint.setColor(mTextColor);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setAntiAlias(true);
mTextPaint.setDither(true);
mTextPaint.setTextSize(mTextSize);
}
重點代碼結束,自定義這個波浪并沒有什么特別的,重點就是,貝塞爾曲線,其他的,都不難偶。~~
下一帖預告,看看 intent中,類做什么的。