Android仿酷狗音樂自定義側滑菜單控件簡單實現

隨著Android的不斷成熟,許多絢麗的效果也在不斷的被大家開發出來,其中側滑的效果用到的項目很多,用的好的更是給吸引了很多用戶。國內像QQ和酷狗App的側滑就很給力,所以查了一些資料,并結合ViewDragHelper輔助類,做了一種比較簡單的側滑實現方式。

學習Android的同學注意了!!!

學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Android學習交流群,群號碼:364595326? 我們一起學Android!

一、實現效果圖

實現的效果基本跟酷狗App差不多,因為就是仿造酷狗的~~

二、實現原理

SlideLayout控件使用的是ViewDragHelper輔助類來實現的。ViewDragHelper是一個實現View的拖拽的神器,它把View的拖拽操作變得特別的簡單,不熟悉ViewDragHelper的同學請先上傳送門

要實現拖拽,首先需要將SlideLayout和ViewDragHelper關聯起來,然后將SlideLayout的事件交給ViewDragHelper來處理,然后在ViewDragHelper提供的回調里就可以對View進行各種操作。不過拖拽的原理都是差不多的,通過水平或者豎直的移動ViewGroup,然后不斷的layout和invalidate進行重繪顯示。

在滑動的過程中,除了要不斷的計算滑動的位置和重繪界面,還需要對子容器進行不同的動畫操作,這里使用的是ViewHelper類對View做平移縮放和漸變等動畫。

另外還使用枚舉來記錄SlideLayout側滑的狀態,包括關閉,打開和正在滑動。并且提供PanelSlideListener監聽滑動的狀態。這樣就可以根據不同的狀態做不同的操作。比如手動打開側滑,關閉側滑等等。

三、邏輯分析

這個項目實現的邏輯其實并不難,只需要計算出ViewGroup滑動的位置,然后重繪就行,其次還需要計算控件縮放和拉伸的比例等等。當然對各種View的操作方法還是要比較熟悉,不然搞不明白有些邏輯要做這里做。

1. SlideLayout應該作為一個控件容器來包容兩個子容器,一個菜單容器,一個主容器,首先我們需要獲取SlideLayout容器的寬高和兩個子容器對象

在View的onSizeChanged()方法里獲取SlideLayout的寬高,此時控件已經測量完成

/**

* 當控件的寬高發生變化時會回調這個方法,可以用來測量控件的寬高

*

* @param w

* @param h

* @param oldw

* @param oldh

*/

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

mSlideHeight = getMeasuredHeight();

mSlideWidth = getMeasuredWidth();

/**

* 初始化拖動的范圍

* 默認為屏幕寬度的60%

*/

mSlideRange = (int) (mSlideWidth * mRangePercent);

}

在View的onFinishInflate()方法里可以獲取容器對象,此時布局已經填充

/**

* 當View填充結束時會調用這個方法,可以獲取子View對象

*/

@Override

protected void onFinishInflate() {

super.onFinishInflate();

if (getChildCount() < 2) {

throw new IllegalStateException("SlideLayout控件的子View必須大于2個");

}

if (!((getChildAt(0) instanceof ViewGroup) && (getChildAt(1) instanceof ViewGroup))) {

throw new IllegalArgumentException("SlideLayout控件的子View必須是ViewGroup");

}

mMenuContainer = (ViewGroup) getChildAt(0);

mMainContainer = (ViewGroup) getChildAt(1);

}

2. 獲取到了需要的屬性和對象之后,就可以將SlideLayout和ViewDragHelper進行綁定

首先在控件的構造里創建ViewDragHelper對象,創建完之后會有一個回調,而我們對View的各種操作就是在回調的各種方法里進行的

/** View的滑動的輔助類,在回調里監聽View的各種操作

* @param forParent 要進行觸摸滑動的父控件

* @param sensitivity 控件滑動的速度,敏感度,1.0f正常

* @param cb? 對View的事件發生改變的回調

*/

mDragHelper = ViewDragHelper.create(this, 1.0f, mViewCallback);

創建對象之后,如果此時就對View進行操作是沒有效果的,因為還需要把SlideLayout的處理事件傳遞給ViewDragHelper

/**

* 轉交攔截事件給輔助類

*

* @param ev

* @return

*/

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

final int action = MotionEventCompat.getActionMasked(ev);

if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {

mDragHelper.cancel();

return false;

}

return mDragHelper.shouldInterceptTouchEvent(ev);

}

/**

* 轉交觸摸事件給輔助類

*

* @param event

* @return

*/

@Override

public boolean onTouchEvent(MotionEvent event) {

try {

mDragHelper.processTouchEvent(event);

} catch (Exception e) {

e.printStackTrace();

}

return true;

}

最重要的地方就是ViewDragHelper的回調了,里面有很多方法,每一個都很重要,這里列舉一個對容器的滑動處理方法onViewPositionChanged()。其實邏輯也是比較簡單,就是判斷當前滑動的是哪一個容器,計算容器的左邊界值,然后對容器進行重繪

/**

* 當子View的位置發送改變時回調

* @param changedView 改變的子View

* @param left 距離左邊界距離

* @param top 距離頂部距離

* @param dx 水平滑動距離差

* @param dy 豎直滑動距離差

*/

@Override

public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {

/**

* 將菜單面板的移動量給主面板

*/

if (changedView == mMenuContainer) {

mMenuContainer.layout(0, 0, mSlideWidth, mSlideHeight);

int newLeft = mMainContainer.getLeft() + dx;

newLeft = fixLeft(newLeft);

mMainContainer.layout(newLeft, 0, newLeft + mSlideWidth, mSlideHeight);

}

// 處理移動事件

performSlideEvent();

}

五、使用教程

布局文件中

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/slideLayout"

android:layout_width="match_parent"

android:background="@mipmap/icon_bg"

android:layout_height="match_parent">

// 菜單容器

// 主容器

代碼中獲取對象,設置監聽,設置打開或者關閉側滑

六、總結

有了ViewDragHelper這個輔助類,對ViewGroup進行操作相對來說已經比較簡單了,只需要處理計算和繪制的工作,其他的都已經做好了。當然ViewDragHelper的作用遠不于此,想要了解更多的同學可以去研究一下這個類的源碼。這里也只是簡單的實現了側滑功能,要想做的更完美的同學

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容