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的作用遠不於此,想要了解更多的同學可以去研究一下這個類的源碼。這裏也只是簡單的實現了側滑功能,要想做的更完美的同學

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章