国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

Android自定義View實(shí)現(xiàn)角度選擇器

2019-12-12 04:46:58
字體:
供稿:網(wǎng)友

首先來看一下Google Photos的效果

實(shí)現(xiàn)最終的效果:

實(shí)現(xiàn)思路

仔細(xì)觀察這個(gè)效果,先分析構(gòu)成結(jié)構(gòu),我把它分成三部分:

    1、表示刻度的點(diǎn)

    2、相應(yīng)點(diǎn)上方的數(shù)字

    3、控件中央的當(dāng)前刻度與三角

可以看出,構(gòu)成元素十分簡(jiǎn)單,不涉及圖片,Drawable,那么只需要用Canvas畫出來就好了。

接下來觀察手勢(shì)的操作,查看隨著手指滑動(dòng),控件做出的變化,這里的變化有:

     1、手指按上去時(shí),部分區(qū)域變亮(部分區(qū)域即為可見區(qū)域)

     2、隨著手指滑動(dòng),相應(yīng)的數(shù)字發(fā)生移動(dòng),當(dāng)前角度值也發(fā)生改變

     3、離中心越近,透明度越低,且0°的下方的點(diǎn)要大一些

好了,我們對(duì)這個(gè)控件已經(jīng)分析的很透徹了,根據(jù)分析,首先我們要在View的onDraw()方法中畫出構(gòu)成元素,之后要讓它動(dòng)起來,在onTouchEvent()方法中監(jiān)聽手勢(shì),改變一些值并重繪我們的View,這里很明顯,我們要改變的肯定是當(dāng)前角度這個(gè)值。

動(dòng)手

既然有了思路,那么就要馬上動(dòng)手,不然下次忘記掉了怎么辦?

畫點(diǎn)

首先,先把點(diǎn)給畫出來,位置很簡(jiǎn)單,肯定是從視圖中心開始畫,往左往右分別畫點(diǎn)。

for (int i = 0; i < mPointCount; i++) { canvas.getClipBounds(mCanvasClipBounds); canvas.drawPoint(mCanvasClipBounds.centerX() + (i - mPointCount / 2) * mPointMargin,     mCanvasClipBounds.centerY(), mPointPaint);}

其中mPointCount為所要畫的點(diǎn)個(gè)數(shù),這里默認(rèn)為51個(gè),mPointMargin為兩點(diǎn)間的邊距,長(zhǎng)度為View的寬度除以點(diǎn)的個(gè)數(shù)。

看看效果

嗯,成功的把點(diǎn)給畫出來了。

畫刻度上方的數(shù)字

既然把點(diǎn)給畫出來了,根據(jù)我們的思路,我們要把數(shù)字給畫到正確的位置上,畫數(shù)字當(dāng)然很簡(jiǎn)單,這里難的是找到正確的位置。

首先,我們的數(shù)字是會(huì)移動(dòng)的,隨著當(dāng)前角度的不同,所展示的數(shù)字大小位置都不同。但毫無疑問的是,這個(gè)位置(x坐標(biāo))肯定是關(guān)于當(dāng)前角度的一個(gè)函數(shù)。至于具體是一個(gè)什么樣的函數(shù),相信聰明的你很快就可以分析出來,畢竟只是一個(gè)線性關(guān)系,這里就直接貼代碼了。

private void drawDegreeText(int degrees, Canvas canvas, boolean canReach) { canvas.drawText(degrees + "°",    getWidth() / 2 + mPointMargin * degrees / 2 - mTextWidths[0] / 2 * 3 - mCurrentDegrees / 2 * mPointMargin,     getHeight() / 2 - 10,     mTextPaint); }}

按照我們的效果,我們需要畫出-90°~90°的刻度,其中-45°~45°是可到達(dá)角度,另外的角度不可到達(dá)。

drawDegreeText(0, canvas, true);drawDegreeText(15, canvas, true);drawDegreeText(30, canvas, true);drawDegreeText(45, canvas, true);drawDegreeText(-15, canvas, true);drawDegreeText(-30, canvas, true);drawDegreeText(-45, canvas, true);drawDegreeText(60, canvas, false);drawDegreeText(75, canvas, false);drawDegreeText(90, canvas, false);drawDegreeText(-60, canvas, false);drawDegreeText(-75, canvas, false);drawDegreeText(-90, canvas, false);

好了,來看一下效果,可以看到,數(shù)字被畫在了正確的位置。

畫當(dāng)前角度

這個(gè)超級(jí)簡(jiǎn)單呢,位置也特別好確定,上方三角形的Path也非常好知道,但是這里要注意的是,當(dāng)當(dāng)前角度為0°左右時(shí),不應(yīng)該把0°刻度顯示出來。

//畫當(dāng)前角度if (mCurrentDegrees >= 10) { canvas.drawText(mCurrentDegrees + "°", getWidth() / 2 - mTextWidths[0], mBaseLine, mTextPaint);} else if (mCurrentDegrees <= -10) { canvas.drawText(mCurrentDegrees + "°", getWidth() / 2 - mTextWidths[0] / 2 * 3, mBaseLine, mTextPaint);} else if (mCurrentDegrees < 0) { canvas.drawText(mCurrentDegrees + "°", getWidth() / 2 - mTextWidths[0], mBaseLine, mTextPaint);} else { canvas.drawText(mCurrentDegrees + "°", getWidth() / 2 - mTextWidths[0] / 2, mBaseLine, mTextPaint);}//三角指示器的PathmIndicatorPath.moveTo(w / 2, h / 2 + mFontMetrics.top / 2 - 18);mIndicatorPath.rLineTo(-8, -8);mIndicatorPath.rLineTo(16, 0);

還有一個(gè)小細(xì)節(jié),就是離中心越近,其透明度越來越低,也就是說,我們要根據(jù)離中心的位置,來改變畫筆Paint的alpha值,再將點(diǎn)畫出。

 for (int i = 0; i < mPointCount; i++) {  if (i > zeroIndex - 22 && i < zeroIndex + 22 && mScrollStarted) {   mPointPaint.setAlpha(255);  } else {   mPointPaint.setAlpha(100);  }  if (i > mPointCount / 2 - 8 && i < mPointCount / 2 + 8    && i > zeroIndex - 22 && i < zeroIndex + 22) {   if (mScrollStarted)    mPointPaint.setAlpha(Math.abs(mPointCount / 2 - i) * 255 / 8);   else    mPointPaint.setAlpha(Math.abs(mPointCount / 2 - i) * 100 / 8);  }  …… }

這時(shí),已經(jīng)很像了,只是還不能動(dòng)。

動(dòng)起來

該繪制的部分我們已經(jīng)都繪制起來了,是時(shí)候讓這個(gè)View動(dòng)起來了,角度選擇器的觸摸事件不復(fù)雜,我們只需要在我們移動(dòng)手指的時(shí)候根據(jù)滑動(dòng)距離來改變當(dāng)前角度值并重繪視圖就可以看到移動(dòng)效果了。為什么呢?因?yàn)槲覀冎霸诋嫈?shù)字的時(shí)候,位置都是由當(dāng)前角度這個(gè)值決定的,所以它一發(fā)生變化,數(shù)字的位置也會(huì)發(fā)生改變。

@Overridepublic boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) {  ……  case MotionEvent.ACTION_MOVE:   float distance = event.getX() - mLastTouchedPosition;   ……   if (distance != 0) {    onScrollEvent(event, distance);   }   break;  }  ……  return true;}private void onScrollEvent(MotionEvent event, float distance) { mTotalScrollDistance -= distance; postInvalidate(); mLastTouchedPosition = event.getX(); mCurrentDegrees = (int) ((mTotalScrollDistance * mDragFactor) / mPointMargin); if (mScrollingListener != null) {  mScrollingListener.onScroll(mCurrentDegrees); }}

當(dāng)然你還需要處理一些細(xì)節(jié)性的東西,比如在數(shù)字移動(dòng)的時(shí)候,靠近中心一定范圍就會(huì)消失(透明度變?yōu)?),這些都是很容易控制的,只要改變畫筆的透明度就好了,但是正是對(duì)細(xì)節(jié)的把控,才能做出一個(gè)效果讓用戶滿意的自定義View。最后,再來看一下效果。

擴(kuò)展

到這里,我們做的角度選擇器已經(jīng)和Google Photos的幾乎一模一樣了,但是,僅僅這樣就夠了。不,不夠,我們還要繼續(xù)擴(kuò)展,為什么只能達(dá)到正負(fù)45°,我們要所有的范圍自由選擇,也就是-180°~180°,然后數(shù)字顏色啊,點(diǎn)的顏色啊都要讓人自由選擇。所以我們要擴(kuò)展我們的角度選擇器,把一切可以變化的接口暴露出來。

最后看一下我們多種多樣的角度選擇器,還是挺好看呀~

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,這次的自定義View相對(duì)于前兩次的來說,無疑是簡(jiǎn)單了很多,只運(yùn)用了最基礎(chǔ)的繪圖知識(shí)和事件機(jī)制,但是看起來效果也還不錯(cuò)哦,嘿嘿,反正我特別喜歡這個(gè)角度選擇器,雖然我還不知道除了裁圖頁(yè)面可以用到還有哪里可以用到。所以說運(yùn)用最簡(jiǎn)單的知識(shí),也可以組合出比較復(fù)雜的效果,希望大家多發(fā)揮自己的想象力,一起自定義出更多好玩的,實(shí)用的,酷炫的控件吧。希望這篇文章對(duì)你有幫助,哪怕只是一些啟發(fā),也是值得的。如果有疑問大家也可以留言交流。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 汉源县| 藁城市| 石景山区| 蕉岭县| 石棉县| 四子王旗| 石河子市| 安新县| 宁津县| 南昌市| 新乐市| 新昌县| 灵石县| 利津县| 阿克苏市| 松阳县| 岳池县| 阜新市| 永顺县| 禹城市| 江门市| 镇安县| 甘孜| 娄烦县| 井陉县| 裕民县| 福安市| 新郑市| 洪泽县| 万州区| 平原县| 基隆市| 新龙县| 鹿邑县| 北安市| 瑞昌市| 巨野县| 浦东新区| 大渡口区| 西华县| 彭泽县|