隨著Android的不斷成熟易核,許多絢麗的效果也在不斷的被大家開發(fā)出來嗅蔬,其中側(cè)滑的效果用到的項目很多蜘渣,用的好的更是給吸引了很多用戶济蝉。國內(nèi)像QQ和酷狗App的側(cè)滑就很給力杰刽,所以查了一些資料,并結(jié)合ViewDragHelper輔助類王滤,做了一種比較簡單的側(cè)滑實現(xiàn)方式贺嫂。
學習Android的同學注意了!J缙汀涝婉!
學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Android學習交流群蔗怠,群號碼:364595326? 我們一起學Android墩弯!
一、實現(xiàn)效果圖
實現(xiàn)的效果基本跟酷狗App差不多寞射,因為就是仿造酷狗的~~
二渔工、實現(xiàn)原理
SlideLayout控件使用的是ViewDragHelper輔助類來實現(xiàn)的。ViewDragHelper是一個實現(xiàn)View的拖拽的神器桥温,它把View的拖拽操作變得特別的簡單引矩,不熟悉ViewDragHelper的同學請先上傳送門。
要實現(xiàn)拖拽,首先需要將SlideLayout和ViewDragHelper關(guān)聯(lián)起來旺韭,然后將SlideLayout的事件交給ViewDragHelper來處理氛谜,然后在ViewDragHelper提供的回調(diào)里就可以對View進行各種操作。不過拖拽的原理都是差不多的区端,通過水平或者豎直的移動ViewGroup,然后不斷的layout和invalidate進行重繪顯示值漫。
在滑動的過程中,除了要不斷的計算滑動的位置和重繪界面织盼,還需要對子容器進行不同的動畫操作杨何,這里使用的是ViewHelper類對View做平移縮放和漸變等動畫。
另外還使用枚舉來記錄SlideLayout側(cè)滑的狀態(tài)沥邻,包括關(guān)閉危虱,打開和正在滑動。并且提供PanelSlideListener監(jiān)聽滑動的狀態(tài)唐全。這樣就可以根據(jù)不同的狀態(tài)做不同的操作埃跷。比如手動打開側(cè)滑,關(guān)閉側(cè)滑等等芦瘾。
三捌蚊、邏輯分析
這個項目實現(xiàn)的邏輯其實并不難集畅,只需要計算出ViewGroup滑動的位置近弟,然后重繪就行,其次還需要計算控件縮放和拉伸的比例等等挺智。當然對各種View的操作方法還是要比較熟悉祷愉,不然搞不明白有些邏輯要做這里做。
1. SlideLayout應(yīng)該作為一個控件容器來包容兩個子容器赦颇,一個菜單容器二鳄,一個主容器,首先我們需要獲取SlideLayout容器的寬高和兩個子容器對象
在View的onSizeChanged()方法里獲取SlideLayout的寬高媒怯,此時控件已經(jīng)測量完成
/**
* 當控件的寬高發(fā)生變化時會回調(diào)這個方法订讼,可以用來測量控件的寬高
*
* @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()方法里可以獲取容器對象,此時布局已經(jīng)填充
/**
* 當View填充結(jié)束時會調(diào)用這個方法扇苞,可以獲取子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進行綁定
首先在控件的構(gòu)造里創(chuàng)建ViewDragHelper對象,創(chuàng)建完之后會有一個回調(diào)鳖敷,而我們對View的各種操作就是在回調(diào)的各種方法里進行的
/** View的滑動的輔助類脖苏,在回調(diào)里監(jiān)聽View的各種操作
* @param forParent 要進行觸摸滑動的父控件
* @param sensitivity 控件滑動的速度,敏感度定踱,1.0f正常
* @param cb? 對View的事件發(fā)生改變的回調(diào)
*/
mDragHelper = ViewDragHelper.create(this, 1.0f, mViewCallback);
創(chuàng)建對象之后棍潘,如果此時就對View進行操作是沒有效果的,因為還需要把SlideLayout的處理事件傳遞給ViewDragHelper
/**
* 轉(zhuǎn)交攔截事件給輔助類
*
* @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);
}
/**
* 轉(zhuǎn)交觸摸事件給輔助類
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
mDragHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
最重要的地方就是ViewDragHelper的回調(diào)了,里面有很多方法亦歉,每一個都很重要恤浪,這里列舉一個對容器的滑動處理方法onViewPositionChanged()。其實邏輯也是比較簡單肴楷,就是判斷當前滑動的是哪一個容器资锰,計算容器的左邊界值,然后對容器進行重繪
/**
* 當子View的位置發(fā)送改變時回調(diào)
* @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">
// 菜單容器
// 主容器
代碼中獲取對象绷杜,設(shè)置監(jiān)聽,設(shè)置打開或者關(guān)閉側(cè)滑
六濒募、總結(jié)
有了ViewDragHelper這個輔助類鞭盟,對ViewGroup進行操作相對來說已經(jīng)比較簡單了,只需要處理計算和繪制的工作瑰剃,其他的都已經(jīng)做好了齿诉。當然ViewDragHelper的作用遠不于此,想要了解更多的同學可以去研究一下這個類的源碼晌姚。這里也只是簡單的實現(xiàn)了側(cè)滑功能粤剧,要想做的更完美的同學