編輯:關於Android編程
首先來看一下Google Photos的效果
實現最終的效果:
實現思路
仔細觀察這個效果,先分析構成結構,我把它分成三部分:
1、表示刻度的點
2、相應點上方的數字
3、控件中央的當前刻度與三角
可以看出,構成元素十分簡單,不涉及圖片,Drawable,那麼只需要用Canvas畫出來就好了。
接下來觀察手勢的操作,查看隨著手指滑動,控件做出的變化,這裡的變化有:
1、手指按上去時,部分區域變亮(部分區域即為可見區域)
2、隨著手指滑動,相應的數字發生移動,當前角度值也發生改變
3、離中心越近,透明度越低,且0°的下方的點要大一些
好了,我們對這個控件已經分析的很透徹了,根據分析,首先我們要在View的onDraw()
方法中畫出構成元素,之後要讓它動起來,在onTouchEvent()
方法中監聽手勢,改變一些值並重繪我們的View,這裡很明顯,我們要改變的肯定是當前角度這個值。
動手
既然有了思路,那麼就要馬上動手,不然下次忘記掉了怎麼辦?
畫點
首先,先把點給畫出來,位置很簡單,肯定是從視圖中心開始畫,往左往右分別畫點。
for (int i = 0; i < mPointCount; i++) { canvas.getClipBounds(mCanvasClipBounds); canvas.drawPoint(mCanvasClipBounds.centerX() + (i - mPointCount / 2) * mPointMargin, mCanvasClipBounds.centerY(), mPointPaint); }
其中mPointCount為所要畫的點個數,這裡默認為51個,mPointMargin為兩點間的邊距,長度為View的寬度除以點的個數。
看看效果
嗯,成功的把點給畫出來了。
畫刻度上方的數字
既然把點給畫出來了,根據我們的思路,我們要把數字給畫到正確的位置上,畫數字當然很簡單,這裡難的是找到正確的位置。
首先,我們的數字是會移動的,隨著當前角度的不同,所展示的數字大小位置都不同。但毫無疑問的是,這個位置(x坐標)肯定是關於當前角度的一個函數。至於具體是一個什麼樣的函數,相信聰明的你很快就可以分析出來,畢竟只是一個線性關系,這裡就直接貼代碼了。
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°是可到達角度,另外的角度不可到達。
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);
好了,來看一下效果,可以看到,數字被畫在了正確的位置。
畫當前角度
這個超級簡單呢,位置也特別好確定,上方三角形的Path也非常好知道,但是這裡要注意的是,當當前角度為0°左右時,不應該把0°刻度顯示出來。
//畫當前角度 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); } //三角指示器的Path mIndicatorPath.moveTo(w / 2, h / 2 + mFontMetrics.top / 2 - 18); mIndicatorPath.rLineTo(-8, -8); mIndicatorPath.rLineTo(16, 0);
還有一個小細節,就是離中心越近,其透明度越來越低,也就是說,我們要根據離中心的位置,來改變畫筆Paint的alpha值,再將點畫出。
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); } …… }
這時,已經很像了,只是還不能動。
動起來
該繪制的部分我們已經都繪制起來了,是時候讓這個View動起來了,角度選擇器的觸摸事件不復雜,我們只需要在我們移動手指的時候根據滑動距離來改變當前角度值並重繪視圖就可以看到移動效果了。為什麼呢?因為我們之前在畫數字的時候,位置都是由當前角度這個值決定的,所以它一發生變化,數字的位置也會發生改變。
@Override public 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); } }
當然你還需要處理一些細節性的東西,比如在數字移動的時候,靠近中心一定范圍就會消失(透明度變為0),這些都是很容易控制的,只要改變畫筆的透明度就好了,但是正是對細節的把控,才能做出一個效果讓用戶滿意的自定義View。最後,再來看一下效果。
擴展
到這裡,我們做的角度選擇器已經和Google Photos的幾乎一模一樣了,但是,僅僅這樣就夠了。不,不夠,我們還要繼續擴展,為什麼只能達到正負45°,我們要所有的范圍自由選擇,也就是-180°~180°,然後數字顏色啊,點的顏色啊都要讓人自由選擇。所以我們要擴展我們的角度選擇器,把一切可以變化的接口暴露出來。
最後看一下我們多種多樣的角度選擇器,還是挺好看呀~
總結
以上就是這篇文章的全部內容了,這次的自定義View相對於前兩次的來說,無疑是簡單了很多,只運用了最基礎的繪圖知識和事件機制,但是看起來效果也還不錯哦,嘿嘿,反正我特別喜歡這個角度選擇器,雖然我還不知道除了裁圖頁面可以用到還有哪裡可以用到。所以說運用最簡單的知識,也可以組合出比較復雜的效果,希望大家多發揮自己的想象力,一起自定義出更多好玩的,實用的,酷炫的控件吧。希望這篇文章對你有幫助,哪怕只是一些啟發,也是值得的。如果有疑問大家也可以留言交流。
前言本自定義控件參考自鴻洋大神的自定義控件,基於原來的控件效果進行修改,著重實現了以下效果:位置自動修正以及滑動結束的回調。我們先來看看效果圖:上面的圖片是一個Image
本文實例講述了android通過Location API顯示地址信息的實現方法。分享給大家供大家參考。具體如下:android的Locatin API,可以通過Geoco
在學習Android開發的過程你,你往往會去借鑒別人的應用是怎麼開發的,那些漂亮的動畫和精致的布局可能會讓你愛不釋手,作為一個開發者,你可能會很想知道這些效果界面是怎麼去
先給大家展示下效果圖,如果感覺不錯,請參考實現思路:我們要實現一個自定義的再一個圓形中繪制一個弧形的自定義View,思路是這樣的: 先要創建一個類ProgressVie