大家好!我是一名執(zhí)著的Android開(kāi)發(fā)攻城獅坚俗,第一次寫(xiě)簡(jiǎn)書(shū)镜盯,沒(méi)有寫(xiě)好的希望大家多多包涵,萬(wàn)事開(kāi)頭難猖败,從去年開(kāi)始我就想寫(xiě)點(diǎn)自己的東西速缆,但是一直沒(méi)有寫(xiě)下去的勇氣和毅力,希望這是我一個(gè)好的習(xí)慣開(kāi)始恩闻。在這我先模仿一個(gè)艺糜,貝塞爾曲線的基本原理,在這里我就不說(shuō)了幢尚,不論簡(jiǎn)書(shū)還是其他論壇上都有很多介紹破停,在這里我推薦:Android -- 貝塞爾曲線公式的推導(dǎo)和簡(jiǎn)單使用,寫(xiě)的還是很不錯(cuò)的尉剩,當(dāng)然也有其他大神寫(xiě)的真慢,在這就不一一列舉了,百度一下理茎,一大篇黑界。
先說(shuō)下我我編寫(xiě)的步驟和思路,完整的代碼在最后面:
1皂林、我需要哪些來(lái)輔助我實(shí)現(xiàn)“圓漸變心”朗鸠,第一個(gè)就是我需要一個(gè)坐標(biāo)系(mCentreX,mCentreY)
canvas.drawLine(0,mCentreY,viewWidth,mCentreY,mCoordinatePaint);
canvas.drawLine(mCentreX,0,mCentreX,viewHigh,mCoordinatePaint);
2、我需要貝塞爾三階曲線來(lái)畫(huà)圓础倍,實(shí)際上就和貝塞爾二階曲線兩個(gè)數(shù)據(jù)控制點(diǎn)一樣童社,我將圓劃分為四塊
每塊一個(gè)貝塞爾三階曲線圓弧。所以需要4個(gè)數(shù)據(jù)點(diǎn)著隆,八個(gè)控制點(diǎn)
//添加數(shù)據(jù)點(diǎn)
mPointDatas.add(newPointF(mCentreX,mCentreY-mControlRadius));
mPointDatas.add(newPointF(mCentreX+mControlRadius,mCentreY));
mPointDatas.add(newPointF(mCentreX,mCentreY+mControlRadius));
mPointDatas.add(newPointF(mCentreX-mControlRadius,mCentreY));
//添加控制點(diǎn)
mPointControlls.add(newPointF(mCentreX+mControlRadius*stu,mCentreY-mControlRadius));
mPointControlls.add(newPointF(mCentreX+mControlRadius,mCentreY-mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX+mControlRadius,mCentreY+mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX+mControlRadius*stu,mCentreY+mControlRadius));
mPointControlls.add(newPointF(mCentreX-mControlRadius*stu,mCentreY+mControlRadius));
mPointControlls.add(newPointF(mCentreX-mControlRadius,mCentreY+mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX-mControlRadius,mCentreY-mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX-mControlRadius*stu,mCentreY-mControlRadius));
坐標(biāo)系上的四個(gè)點(diǎn)位為數(shù)據(jù)點(diǎn)扰楼,其他點(diǎn)為控制點(diǎn)呀癣。然后一個(gè)貝塞爾三階曲線畫(huà)出四分之一圓弧
然后循環(huán)畫(huà)出圓
//貝塞爾三階曲線
for(inti =0; i
if(i < (mPointDatas.size() -1)) {
Pathpath =newPath();
path.moveTo(mPointDatas.get(i).x,mPointDatas.get(i).y);
path.cubicTo(mPointControlls.get(i*2).x,mPointControlls.get(i*2).y,mPointControlls.get(i*2+1).x,mPointControlls.get(i*2+1).y,
mPointDatas.get(i+1).x,mPointDatas.get(i+1).y);
//繪制路徑
canvas.drawPath(path,mPaintBezier);
}else{
Pathpath =newPath();
path.moveTo(mPointDatas.get(i).x,mPointDatas.get(i).y);
path.cubicTo(mPointControlls.get(i*2).x,mPointControlls.get(i*2).y,mPointControlls.get(i*2+1).x,mPointControlls.get(i*2+1).y,
mPointDatas.get(0).x,mPointDatas.get(0).y);
//繪制路徑
canvas.drawPath(path,mPaintBezier);
}
}
3、最后一塊就是圓邊成心操作弦赖,數(shù)據(jù)點(diǎn)我們需要操作最頂端的一個(gè)數(shù)據(jù)點(diǎn)就好项栏,控制點(diǎn)也只需要操作下面四個(gè)數(shù)據(jù)點(diǎn)即可
if(count*rate<100) {
mPointDatas.get(0).y=mPointDatas.get(0).y+1f*rate;
mPointControlls.get(2).x=mPointControlls.get(2).x-0.2f*rate;
mPointControlls.get(3).y=mPointControlls.get(3).y-0.8f*rate;
mPointControlls.get(4).y=mPointControlls.get(4).y-0.8f*rate;
mPointControlls.get(5).x=mPointControlls.get(5).x+0.2f*rate;
invalidate();
count++;
handler.postDelayed(this,50);
}
設(shè)置一個(gè)定時(shí)器執(zhí)行上面重復(fù)執(zhí)行上面操作就可以實(shí)現(xiàn)圓邊心
以上就實(shí)現(xiàn)了貝塞爾曲線——圓漸變心,下面是全部主要代碼(代碼里有擴(kuò)展實(shí)現(xiàn)變四葉草蹬竖、變水滴):
//畫(huà)布大小
private intviewWidth,viewHigh;
//畫(huà)布中心點(diǎn)坐標(biāo)
private intmCentreX,mCentreY;
//坐標(biāo)畫(huà)筆
privatePaintmCoordinatePaint;
//控制點(diǎn)沼沈、數(shù)據(jù)點(diǎn)畫(huà)筆
privatePaintmPaintPoint;
//畫(huà)圓畫(huà)筆
privatePaintmPaintBezier;
//數(shù)據(jù)點(diǎn)半徑
private intmControlRadius=200;
//放置四個(gè)數(shù)據(jù)點(diǎn)的集合
privateListmPointDatas;
//方式8個(gè)控制點(diǎn)的集合
privateListmPointControlls;
//常量0.552284749831
private floatstu=0.552284749831f;
//圓變心進(jìn)行變化計(jì)數(shù)
private intcount=0;
//變化類型
private intchangeType=0;
//變化速率
private floatrate=5f;
publicBezierCurveThreeView(Contextcontext) {
super(context);
}
publicBezierCurveThreeView(Contextcontext,AttributeSetattrs) {
super(context,attrs);
initPaint();
}
publicBezierCurveThreeView(Contextcontext,AttributeSetattrs,intdefStyleAttr) {
super(context,attrs,defStyleAttr);
}
private voidinitPaint(){
count=0;
//初始化坐標(biāo)畫(huà)筆
mCoordinatePaint=newPaint();
mCoordinatePaint.setStyle(Paint.Style.STROKE);
mCoordinatePaint.setColor(Color.BLACK);
mCoordinatePaint.setStrokeWidth(2);
//初始化控制點(diǎn)、數(shù)據(jù)點(diǎn)畫(huà)筆
mPaintPoint=newPaint();
mPaintPoint.setColor(Color.BLACK);
mPaintPoint.setStrokeWidth(10);
mPaintPoint.setStyle(Paint.Style.FILL);
mPaintPoint.setAntiAlias(true);
//畫(huà)圓畫(huà)筆
mPaintBezier=newPaint();
mPaintBezier.setStyle(Paint.Style.STROKE);
mPaintBezier.setColor(Color.RED);
mPaintBezier.setStrokeWidth(5);
mPaintBezier.setAntiAlias(true);
//初始化數(shù)據(jù)點(diǎn)
mPointDatas=newArrayList<>();
//初始化控制點(diǎn)
mPointControlls=newArrayList<>();
}
@Override
protected voidonSizeChanged(intw,inth,intoldw,intoldh) {
//測(cè)量View寬高
viewWidth=w;
viewHigh=h;
//獲取View中心點(diǎn)
mCentreX=viewWidth/2;
mCentreY=viewHigh/2;
//添加數(shù)據(jù)點(diǎn)
mPointDatas.add(newPointF(mCentreX,mCentreY-mControlRadius));
mPointDatas.add(newPointF(mCentreX+mControlRadius,mCentreY));
mPointDatas.add(newPointF(mCentreX,mCentreY+mControlRadius));
mPointDatas.add(newPointF(mCentreX-mControlRadius,mCentreY));
//添加控制點(diǎn)
mPointControlls.add(newPointF(mCentreX+mControlRadius*stu,mCentreY-mControlRadius));
mPointControlls.add(newPointF(mCentreX+mControlRadius,mCentreY-mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX+mControlRadius,mCentreY+mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX+mControlRadius*stu,mCentreY+mControlRadius));
mPointControlls.add(newPointF(mCentreX-mControlRadius*stu,mCentreY+mControlRadius));
mPointControlls.add(newPointF(mCentreX-mControlRadius,mCentreY+mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX-mControlRadius,mCentreY-mControlRadius*stu));
mPointControlls.add(newPointF(mCentreX-mControlRadius*stu,mCentreY-mControlRadius));
super.onSizeChanged(w,h,oldw,oldh);
}
@Override
protected voidonDraw(Canvascanvas) {
super.onDraw(canvas);
//畫(huà)坐標(biāo)
canvas.drawLine(0,mCentreY,viewWidth,mCentreY,mCoordinatePaint);
canvas.drawLine(mCentreX,0,mCentreX,viewHigh,mCoordinatePaint);
//畫(huà)數(shù)據(jù)點(diǎn)4個(gè)
for(inti =0; i
canvas.drawPoint(mPointDatas.get(i).x,mPointDatas.get(i).y,mPaintPoint);
}
//畫(huà)控制點(diǎn)8個(gè)
for(inti =0; i
canvas.drawPoint(mPointControlls.get(i).x,mPointControlls.get(i).y,mPaintPoint);
}
//貝塞爾三階畫(huà)圓
for(inti =0; i
if(i < (mPointDatas.size() -1)) {
Pathpath =newPath();
path.moveTo(mPointDatas.get(i).x,mPointDatas.get(i).y);
path.cubicTo(mPointControlls.get(i*2).x,mPointControlls.get(i*2).y,mPointControlls.get(i*2+1).x,mPointControlls.get(i*2+1).y,
mPointDatas.get(i+1).x,mPointDatas.get(i+1).y);
//繪制路徑
canvas.drawPath(path,mPaintBezier);
}else{
Pathpath =newPath();
path.moveTo(mPointDatas.get(i).x,mPointDatas.get(i).y);
path.cubicTo(mPointControlls.get(i*2).x,mPointControlls.get(i*2).y,mPointControlls.get(i*2+1).x,mPointControlls.get(i*2+1).y,
mPointDatas.get(0).x,mPointDatas.get(0).y);
//繪制路徑
canvas.drawPath(path,mPaintBezier);
}
}
}
public voidstart(intchangeType){
this.changeType=changeType;
handler.postDelayed(runnable,1000);
}
Handlerhandler=newHandler();
Runnablerunnable=newRunnable() {
@Override
public voidrun() {
if(changeType==0) {//圓變化成心
if(count*rate<100) {
mPointDatas.get(0).y=mPointDatas.get(0).y+1f*rate;
mPointControlls.get(2).x=mPointControlls.get(2).x-0.2f*rate;
mPointControlls.get(3).y=mPointControlls.get(3).y-0.8f*rate;
mPointControlls.get(4).y=mPointControlls.get(4).y-0.8f*rate;
mPointControlls.get(5).x=mPointControlls.get(5).x+0.2f*rate;
invalidate();
count++;
handler.postDelayed(this,50);
}
}else if(changeType==1){//四葉草
if(count*rate<200) {
mPointDatas.get(0).y=mPointDatas.get(0).y+1f*rate;
mPointDatas.get(1).x=mPointDatas.get(1).x-1f*rate;
mPointDatas.get(2).y=mPointDatas.get(2).y-1f*rate;
mPointDatas.get(3).x=mPointDatas.get(3).x+1f*rate;
invalidate();
count++;
handler.postDelayed(this,100);
}
}else if(changeType==2){//水滴
if(count*rate<100) {
mPointDatas.get(0).y=mPointDatas.get(0).y-1f*rate;
mPointDatas.get(1).x=mPointDatas.get(1).x-0.35f*rate;
mPointDatas.get(3).x=mPointDatas.get(3).x+0.35f*rate;
for(inti =0; i
if(i ==0|| i ==1|| i ==6|| i ==7) {
if(mPointControlls.get(i).x>mCentreX) {
mPointControlls.get(i).x=mPointControlls.get(i).x-0.4f*rate;
}else{
mPointControlls.get(i).x=mPointControlls.get(i).x+0.4f*rate;
}
if(mPointControlls.get(i).y>mCentreY) {
mPointControlls.get(i).y=mPointControlls.get(i).y-0.4f*rate;
}else{
mPointControlls.get(i).y=mPointControlls.get(i).y+0.4f*rate;
}
}else if(i ==2|| i ==3|| i ==4|| i ==5) {
if(mPointControlls.get(i).x>mCentreX) {
mPointControlls.get(i).x=mPointControlls.get(i).x-0.2f*rate;
}else{
mPointControlls.get(i).x=mPointControlls.get(i).x+0.2f*rate;
}
if(mPointControlls.get(i).y>mCentreY) {
mPointControlls.get(i).y=mPointControlls.get(i).y-0.2f*rate;
}else{
mPointControlls.get(i).y=mPointControlls.get(i).y+0.2f*rate;
}
}
}
invalidate();
count++;
handler.postDelayed(this,100);
}
}
}
};
本來(lái)想明天在弄好源碼上傳币厕,想想還是立馬上傳了列另,源碼里還有其它兩個(gè)簡(jiǎn)單貝塞爾曲線例子,用以入門(mén)學(xué)習(xí)旦装。
源碼下載
下一期將發(fā)表個(gè)我自己實(shí)現(xiàn)的页衙,Android FrameLayout+ViewDragHelper實(shí)現(xiàn)QQ7.1.0側(cè)滑菜單,提意見(jiàn)阴绢,謝謝店乐!