在此例子中DragViewGroup繼承于LinearLayout
第一步 初始化ViewDragHelper躺枕,在構(gòu)造方法中進(jìn)行
//通過靜態(tài)工廠方法創(chuàng)建
viewDragHelper=ViewDragHelper.create(this,callback);//this指parentView,在這里就是自定義ViewGroup氓栈;callback是使用ViewDragHelper的核心
第二步 攔截事件渣磷,此步驟必不可少
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//事件攔截給viewDragHelper
return viewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//將觸摸事件傳遞給viewDragHelper,此操作必不可少
viewDragHelper.processTouchEvent(event);
return true;
}
第三步 處理computScroll方法授瘦,和使用Scroller一樣幸海,因?yàn)閂iewDragHelper內(nèi)部就是使用了Scroller來實(shí)現(xiàn)的
這里一般情況下可以套用以下模板
@Override
public void computeScroll() {
super.computeScroll();
if(viewDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);//刷新帶有動畫
}
}
- ViewCompat.postInvalidateOnAnimation(this)相當(dāng)于使用scroller的時候必須要調(diào)用invalidate刷新頁面,并且不斷循環(huán)調(diào)用
第四步 也是最關(guān)鍵的一步奥务,處理回調(diào)Callback,在他的內(nèi)部有很多方法物独,我們重寫可以實(shí)現(xiàn)很多效果
- 首先會重寫tryCaptureView方法 ,此方法可以指定哪個View可以被拖動
- 重寫clampViewPositionHorizontal氯葬、clampViewPositionVertical方法可以實(shí)現(xiàn)水平和垂直的滑動挡篓,默認(rèn)返回為0,可以限制滑動區(qū)域
- 重寫onViewCaptured方法可以實(shí)現(xiàn)手指觸摸到View時的效果
- 重寫onViewReleased方法可以實(shí)現(xiàn)手指離開屏幕時的一些功能
- 重寫onViewPositionChanged方法在事件位置變化時可以實(shí)現(xiàn)一些動態(tài)效果
- 重寫onViewDragStateChanged方法在拖拽狀態(tài)變化時調(diào)用
private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return content==child;//判斷是否滑動的子View是內(nèi)容區(qū)域
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {//水平滑動,left表示垂直方向上的位置,dx表示較前次的偏移量
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {//垂直滑動官研,top表示垂直方向上的位置秽澳,dy表示較前次的偏移量
return super.clampViewPositionVertical(child, top, dy);//默認(rèn)為0
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {//手指離開屏幕
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起后緩慢移動到指定位置
if(content.getLeft()<menu.getWidth()/2){
//關(guān)閉菜單
//相當(dāng)于scroller的startScroll方法
viewDragHelper.smoothSlideViewTo(content,0,0);
//刷新帶有動畫
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}else{
//打開菜單
//相當(dāng)于scroller的startScroll方法
viewDragHelper.smoothSlideViewTo(content,menu.getWidth(),0);
//刷新帶有動畫
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
在onFinishInflate方法中按順序定義定義menu,content
在onSizeChanged方法中獲取子View的寬
最終效果就能實(shí)現(xiàn)抽屜式的側(cè)滑菜單
slide.gif
完整代碼如下
public class DragViewGroup extends LinearLayout {
private ViewDragHelper viewDragHelper;
private ViewGroup menu,content;//菜單和內(nèi)容
private int mScreenWidth;
//dp
private int menuRightMargin;
private boolean once;
private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return content==child;//判斷是否滑動的子View是內(nèi)容區(qū)域
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {//水平滑動
return Math.min(Math.max(0,left),mScreenWidth-menuRightMargin);//限制滑動區(qū)域在屏幕左邊距到menu右邊距
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {//垂直滑動
return super.clampViewPositionVertical(child, top, dy);//默認(rèn)為0
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {//手指離開屏幕
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起后緩慢移動到指定位置
if(content.getLeft()<menu.getWidth()/2){
//關(guān)閉菜單
//相當(dāng)于scroller的startScroll方法
viewDragHelper.smoothSlideViewTo(content,0,0);
//刷新帶有動畫
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}else{
//打開菜單
//相當(dāng)于scroller的startScroll方法
viewDragHelper.smoothSlideViewTo(content,menu.getWidth(),0);
//刷新帶有動畫
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
public DragViewGroup(Context context) {
this(context,null);
}
public DragViewGroup(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化viewDragHelper
viewDragHelper=ViewDragHelper.create(this,callback);
WindowManager wm= (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics=new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth=outMetrics.widthPixels;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DragViewGroup);
menuRightMargin= (int) ta.getDimension(R.styleable.DragViewGroup_menuRightMargin,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,getResources().getDisplayMetrics()));
ta.recycle();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
menu= (ViewGroup) getChildAt(0);
content= (ViewGroup) getChildAt(1);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
menu.getLayoutParams().width=mScreenWidth-menuRightMargin;
content.getLayoutParams().width=mScreenWidth;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
content.layout(0,0,content.getWidth(),content.getHeight());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return viewDragHelper.shouldInterceptTouchEvent(ev);//事件攔截給viewDragHelper
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//將觸摸事件傳遞給viewDragHelper戏羽,此操作必不可少
viewDragHelper.processTouchEvent(event);
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if(viewDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);//刷新帶有動畫
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LinearLayout.LayoutParams(getContext(),attrs);
}
}
menu
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img1"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第1個item"
android:layout_toRightOf="@id/img1"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img2"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第2個item"
android:layout_toRightOf="@id/img2"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img3"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第3個item"
android:layout_toRightOf="@id/img3"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img4"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第4個item"
android:layout_toRightOf="@id/img4"
android:layout_centerVertical="true"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img5"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:text="第5個item"
android:layout_toRightOf="@id/img5"
android:layout_centerVertical="true"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.scrollerdemo.MainActivity">
<com.scrollerdemo.DragViewGroup
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
app:menuRightMargin="100dp">
<include layout="@layout/menu" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:gravity="center"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:text="helloworld"
android:textSize="30sp"/>
</LinearLayout>
</com.scrollerdemo.DragViewGroup>
</RelativeLayout>
自定義屬性
<declare-styleable name="DragViewGroup">
<attr name="menuRightMargin" format="dimension"/>
</declare-styleable>
繼續(xù)進(jìn)階担神,為側(cè)滑菜單增加動畫效果
只需要在callback內(nèi)部重寫onViewPositionChanged方法
代碼如下
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
float scale = left * 1f / menu.getWidth();//0 ~ 1
float contentScale = 1 - scale * 0.2f;//1 ~ 0.8
float menuScale = 0.7f + scale * 0.3f;//0.7 ~ 1
float menuAlpha = 0.6f + scale * 0.4f;//0.6 ~ 1
float menuTransX = 0.3f - 0.3f * scale;//0.3 ~ 0
//content
ViewHelper.setPivotX(content, 0);
ViewHelper.setPivotY(content, content.getHeight() / 2);
ViewHelper.setScaleX(content, contentScale);
ViewHelper.setScaleY(content, contentScale);
//menu
ViewHelper.setTranslationX(menu, -menuTransX * menu.getWidth());
ViewHelper.setAlpha(menu, menuAlpha);
ViewHelper.setScaleX(menu, menuScale);
ViewHelper.setScaleY(menu, menuScale);
}
效果如下
slideanim.gif