仿网易云音乐均衡器调节UI效果
介紹
轉載請說明出處!網易云音樂大家都很熟悉,今天主要是來模仿以下他的音效均衡器的調節UI 效果如圖:
? ? ? ?? ? ? ? ? ?
若想實現這個效果我們需要做什么呢?我們現分析一下:
1. 首先定好我們需要畫圖的固定點的坐標(圖中藍色圈)。
2. 過固定點用’平滑曲線‘把這些坐標連接起來?,必須是平滑的哦。
3. 看到效果我們首先想到的就是貝塞爾曲線。
4. 首先我們先把固定點鏈接起來,不讓他動,然后再去實現ontouch()事件,修改坐標點。
我們先繪制過定點的曲線
讓指定的坐標點使用平滑的曲線鏈接起來,這個問題之前看過很多文章,去年都已經做了這樣的需求,只是一直沒時間記錄,過了這么就也忘了差不多,及時把它記下來,如圖:
由圖藍色點是給的坐標點,然后我們根據給的坐標點把,她們平滑的鏈接起來。這里就用到了貝塞爾曲線,如果對自定義view還不是很熟悉的同事,可以去看我的其他文章關于自定義view的專欄。
具體什么是貝塞爾曲線,這里就不說了,推薦大家去看一個文章寫的很好:自帶美感的貝塞爾曲線原理與實戰——Android高級UI
之前我也參考了很多文章,都講了很多的數學公式。
其實我們只要記住1點就行:
任意相鄰的三個點之間第一個點和第三個點的連線和第二個點的切線的斜率是相等的
如圖我們任取其中一段曲線:
注釋:藍色是給的定點,綠色是我們求得的貝塞爾曲線控制點,具體怎么求接下來我們會說,先理解我們的概念
求解控制點
1. 我們知道藍色的點是我們已知的坐標點(x,y),初中學過 y = kx + b; 既然我們定點坐標已知,那我們把這個定點的斜率求出來,然后再根據 (已知斜率 過定點 求一條 直線)這個應該比較容易懂。
2. 通過1 我們能把直線求出來,具體取直線上那一點我們根據曲線的彎曲程度,我們可以定一個比率rate,比如我把比率調的大一點如圖:
?
明顯我們能夠看出綠色的坐標點變長,曲線變得更加彎曲。
所以我們開始計算我們的控制點坐標:
private List<PointF> getControlPoints(PointF[] points){// 計算斜率 y = kx + b => k = (y - b)/xif (points.length < 3){return null;}List<PointF> pointFList = new ArrayList<>();float rate = 0.7f;//從第一個控制點開始計算float cx1 = points[0].x + (points[1].x - points[0].x)*rate;float cy1 = points[0].y;pointFList.add(new PointF(cx1,cy1));for (int i =1;i<points.length-1;i++){//第二個點float k = (points[i+1].y - points[i-1].y)/(points[i+1].x - points[i-1].x);float b = points[i].y - k*points[i].x;//左邊控制點float cxLeft = points[i].x - (points[i].x - points[i-1].x)*rate;float cyLeft = k*cxLeft + b;pointFList.add(new PointF(cxLeft,cyLeft));//右邊控制點float cxRight = points[i].x + (points[i+1].x - points[i].x)*rate;float cyRight = k*cxRight + b;pointFList.add(new PointF(cxRight,cyRight));}//最后一個點float cxLast = points[points.length - 1].x - (points[points.length - 1].x - points[points.length - 2].x)*rate;float cyLast = points[points.length - 1].y;pointFList.add(new PointF(cxLast,cyLast));return pointFList;}得到控制點的坐標然后繪制
這里用到了 path 路徑不理解的可以去看看我以前的文章?Android自定義view --Path 的高級用法之-搜索按鈕動畫
繪制:
for (int i=0;i<mPoints.length-1;i++){mPath.moveTo(mPoints[i].x,mPoints[i].y);mPath.cubicTo(fList.get(i*2).x,fList.get(i*2).y,fList.get(i*2+1).x,fList.get(i*2+1).y,mPoints[i+1].x,mPoints[i+1].y);}到這里平滑曲線我們已經繪制好了,接下來就是ontouch()事件處理拉
onTouch()事件處理
要處理onTouch()事件首先了解的是:
1. View事件分發
2. View 攔截
3. 手指?Action_down 的時候 事件檢測
4. View 事件滑動沖突(這里不存在這個問題)
5. View 消費事件
?不熟悉的同學可以去搜索相關博文,這里就不作詳細的講解
事件分發
事件分發我們首先要想到的方法是 dispatchTouchEvent(MotionEvent event) 在 action_down 的時候 判斷我們的事件該由那個View來消費
@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {int a = event.getAction();switch (a) {case MotionEvent.ACTION_DOWN:x = event.getX();y = event.getY();// 檢測是否需要攔截事件if (!checkClickPosition(x,y)){return false;}}return super.dispatchTouchEvent(event);}記住一句話:任何事件都是從 ACTION_DOWN 開始的,所以不管手指 滑動到何處 ,事件的作用對象 始終是 action_down 處?的 View(如果被當前View攔截的話)
如何檢測(3)
檢測其實就是檢測我們的 ACTION_DOWN 位置 是否在我們事件處理的范圍,比如圖
我們手指點的位置是否在我們的圓環位置內即:手指ACTION_DOWN的坐標(x,y)是否在圓環當前左上角和右下角的(x,y)坐標內,如何計算:
private boolean checkClickPosition(float x,float y){for (int i =0;i<mPoints.length;i++){if ((x < mPoints[i].x +20 && x >mPoints[i].x-20) && (y < mPoints[i].y +20 && y > mPoints[i].y-20)){index = i;return true;}}return false;}這段代碼是我們這個例子的坐標檢測,好好理解理解
View事件消費
消費就其實就是我們調用onTouchEnvent()方法 return true,事件不往下傳遞。
@Overridepublic boolean onTouchEvent(MotionEvent event) {int a = event.getAction();switch (a) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE://處理消費事件的地方mPoints[index].y = event.getY();invalidate();break;case MotionEvent.ACTION_UP:break;}// return true 才會消費return true;}消費比較好理解,就不多說了,到此就是我們仿照網易云音樂的均衡器效果了
看似簡單100多行代碼,其實還是藏著很多重要的知識點的。也是面試容易問到的。
希望大家根據自己的理解去繪制,自己的圖形,直接抄來的就失去他原有的意義。
?
?
?
總結
以上是生活随笔為你收集整理的仿网易云音乐均衡器调节UI效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android仿网易云鲸云音效动效
- 下一篇: 论文常用图表四:Bland-Altman