ViewDragHelper类的使用方法和事件分发机制

ViewDragHelper类的使用方法和事件分发机制的配合

  1. 写一个SlideMenu类,继承自FrameLayout,因为如果继承自ViewGroup的话,需要我们自己来实现onMeasure方法,而该方法的实现一般比较麻烦且没有必要,所以选择继承系统的已有的控件FrameLayout,不用其他控件是因为FrameLayout最轻量级
  2. 在布局文件中给SlideMenu添加2个子布局,分别是菜单的布局和主界面的布局(代码略);
  3. 移动View的方法总结:

    通过改变View的scroll的坐标来移动:
    scrollTo(x,y);//滚动到指定位置
    scrollBy(xOffset,yOffset);//滚动多少距离
    
  4. 通过改变View在父View中的布局的位置:

    offsetLeftAndRight(offset);//同时更改view的left和right
    offsetTopAndBottom(offset);//同时更改view的top和bottom
    layout(l,t,r,b);
    

    但是谷歌发现很多View移动的情景有相识点, 所以封装了ViewDragHelper类来帮助我们在ViewGroup中进行子View的移动:

ViewDragHelper类的介绍

谷歌在2013年I/O开发者大会上提出;

  • 专门用于在ViewGroup中对子View进行拖拽处理;
  • 在19(Android4.4)以及以上的v4包中;
  • 本质是封装了对触摸事件的解析,包括触摸位置,触摸速度以及Scroller的封装,只需要我们在回调方法中指定是否移动,移动多少等等,但是需要注意的是:它只是一个触摸事件的解析类(如GestureDecetor),所以需要我们传递给它触摸事件,它才能工作;

ViewDragHelper类的使用方法

如何创建ViewDragHelper对象

ViewDragHelper viewDragHelper = ViewDragHelper.create(this, callback);

由于ViewDragHelper只是触摸事件解析类,要想让ViewDragHelper工作,需要将触摸事件传递给它

public boolean onInterceptTouchEvent(MotionEvent ev) {
    //让ViewDragHelper帮助我们判断是否应该拦截
    boolean result = viewDragHelper.shouldInterceptTouchEvent(ev);
    return result;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    //将触摸事件传递给ViewDragHelper来解析
    viewDragHelper.processTouchEvent(event);
    return true;
}
重写几个方法
  • 判断是否需要捕获View的触摸事件

    public boolean tryCaptureView(View child, int pointerId)

  • 当一个View被捕获触摸事件时候调用

    public void onViewCaptured(View capturedChild, int activePointerId)

  • 方法名为获取水平方向拖拽的范围,然而目前并没有用,该方法的返回值用来作为判断滑动方向的条件之一

    public int getViewHorizontalDragRange(View child)

  • 用来修正或者指定子View在水平方向上的移动

    public int clampViewPositionHorizontal(View child, int left, int dx)

  • 用来修正或者指定子View在垂直方向上的移动

    public int clampViewPositionVertical(View child, int top, int dy)

  • 当View移动的时候调用

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

  • 当手指从View上抬起的时候回调

    public void onViewReleased(View releasedChild, float xvel, float yvel)

其他的方法

调用方法 :参数需要移动的控件,左上角的原点的坐标

smoothSlideViewTo(View child, int finalLeft, int finalTop)
方法可以使自动移动到某个位置

刷新页面:参数为需要刷新控件的父控件

ViewCompat.postInvalidateOnAnimation(Slidemenu.this);

需要重写view里面的computeScroll()方法才能实现刷新

/**
 * 页面刷新都得走这个方法
 * 刷新方法->draw()->computeScroll
 */
@Override
public void computeScroll() {
    super.computeScroll();
    if (viewDragHelper.continueSettling(true)) {
        ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
    }
}

水平移动的案例

 private ViewDragHelper.Callback callback= new MyCallback();
    private class MyCallback extends ViewDragHelper.Callback{
        /**
     * 判断是否需要捕获View的触摸事件,捕获事件后才可执行下面的方法
     * @param child   当前触摸的View
     * @param pointerId  触摸点索引
     * @return  true:捕获,  false:不捕获.
     */
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
        Log.d(TAG, "tryCaptureView");
        return true;
    }
    /**
     * 当一个View被捕获触摸事件时候调用
     * @param capturedChild 被捕获触摸事件的子View
     * @param activePointerId
     */
    @Override
    public void onViewCaptured(View capturedChild, int activePointerId) {
        Log.d(TAG, "tryConViewCapturedaptureView");
        super.onViewCaptured(capturedChild, activePointerId);
    }
    /**
     * 方法名为获取水平方向拖拽的范围,然而目前并没有用,该方法的返回值用来作为判断滑动方向的条件之一,
     * 如果你想水平移动,那么该方法的返回值最好大于0
     * @param child
     * @return
     */
    @Override
    public int getViewHorizontalDragRange(View child) {
        //Log.d(TAG, "getViewHorizontalDragRange");
        return 1;
    }
    /**
     * 用来修正或者指定子View在水平方向上的移动
     * @param child
     * @param left  是ViewDragHelper帮你计算好的View最新的left的值,left=view.getLeft()+dx
     * @param dx   本次水平移动的距离
     * @return  返回的值表示我们真正想让View的left变成的值
     */
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
        //Log.v(TAG, "clampViewPositionHorizontal");
        return left;
    }
    /**
     * 用来修正或者指定子View在垂直方向上的移动
     * @param
     * @param top  是ViewDragHelper帮你计算好的View最新的top的值,top=view.getTop()+dy
     * @param dy   本次垂直移动的距离
     * @return  返回的值表示我们真正想让View的top变成的值
     */
    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
       // Log.e(TAG, "clampViewPositionVertical");
        return super.clampViewPositionVertical(child, top, dy);
    }


    /**
     * 当View移动的时候调用
     * @param changedView   当前移动的VIew
     * @param left  当前View移动之后最新的left
     * @param top   当前View移动之后最新的top
     * @param dx    水平移动的距离
     * @param dy    垂直移动的距离
     */
    @Override
    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
        Log.d(TAG, "onViewPositionChanged");
        if (changedView==mMainView){

        }
    }
    /**
     * 当手指从View上抬起的时候回调
     * @param releasedChild
     * @param xvel  x方向滑动的速度
     * @param yvel  y方向滑动的速度
     */
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
        Log.v(TAG, "onViewReleased");
        super.onViewReleased(releasedChild, xvel, yvel);
    }
};

事件分发机制

几个重要方法

  • 分发事件

    public boolean dispatchTrackballEvent(MotionEvent event)

  • 拦截事件

    public boolean onInterceptTouchEvent(MotionEvent ev)

  • 处理事件

    public boolean onTouchEvent(MotionEvent event)

ViewGroup中的事件处理的发放

/**
     *分发事件
     * @param event 事件
     */
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {

    return super.dispatchTrackballEvent(event);
}

/**
     *拦截事件
     * @param event 事件
     * @return  返回true 不拦截 ;false拦截
     */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    Log.d(TAG, "是否拦截");
    //让viewDragHelper帮主我们判断是否应该拦截
    return viewDragHelper.shouldInterceptTouchEvent(ev);
}

/**
     *处理事件
     * @param event 事件
     * @return  返回true 自己处理 ;false传递给下一个处理
     */
@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.d(TAG, "onTouchEvent");
    //让ViewDragHelper帮主我们处理触摸事件
    viewDragHelper.processTouchEvent(event);
    return true;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值