Android 貝塞爾曲線——圓漸變心

大家好!我是一名執(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)阴绢,謝謝店乐!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市呻袭,隨后出現(xiàn)的幾起案子眨八,更是在濱河造成了極大的恐慌,老刑警劉巖左电,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件廉侧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡篓足,警方通過(guò)查閱死者的電腦和手機(jī)段誊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纷纫,“玉大人枕扫,你說(shuō)我怎么就攤上這事∪杩” “怎么了烟瞧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)染簇。 經(jīng)常有香客問(wèn)我参滴,道長(zhǎng),這世上最難降的妖魔是什么锻弓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任砾赔,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暴心。我一直安慰自己妓盲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布专普。 她就那樣靜靜地躺著悯衬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪檀夹。 梳的紋絲不亂的頭發(fā)上筋粗,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音炸渡,去河邊找鬼娜亿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蚌堵,可吹牛的內(nèi)容都是我干的买决。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辰斋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼策州!你這毒婦竟也來(lái)了瘸味?” 一聲冷哼從身側(cè)響起宫仗,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旁仿,沒(méi)想到半個(gè)月后藕夫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枯冈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年毅贮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尘奏。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滩褥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炫加,到底是詐尸還是另有隱情瑰煎,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布俗孝,位于F島的核電站酒甸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赋铝。R本人自食惡果不足惜插勤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧农尖,春花似錦析恋、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至窟扑,卻和暖如春喇颁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嚎货。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工橘霎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人殖属。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓姐叁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親洗显。 傳聞我的和親對(duì)象是個(gè)殘疾皇子外潜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容