android: 侧滑菜单的实现(ViewDragHelper)

  • 关于侧滑效果,github上面已经有了很多成型的框架。可以非常方便的集成使用。
  • 不过,实际项目中,可能有些需求,框架并没有帮我们完成。所以,有时候,需要自己动手实现这样的效果。
  • 根据泡网hongyang,还有Android群英传,以及网上各位大婶的博客文章。我写了一个简单的侧滑效果。
  • 记录在此,主要是加深印象。详情在代码注释中
/**
 * Created on 2017/1/24.
 */

public class VdbGroup extends FrameLayout {

    private ViewDragHelper helper;
    private View firstView;
    private View secondView;


    public VdbGroup get() {
        return this;
    }

    public VdbGroup(Context context) {
        this(context, null);
    }

    public VdbGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // record init position of second view
    }

    public VdbGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        helper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == secondView;
            }

            // target child can scroll in x when touch move
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                final int leftBound = firstView.getLeft(); // MainView侧滑的起点
                final int rightBound = firstView.getMeasuredWidth() - leftBound + 10; // 终点 +10 是为了看到效果,实际使用中 去掉 +10 的操作
                final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
                LogUtils.e("newL = " + newLeft + " rb = " + rightBound);
                return newLeft;
            }

            // 子View 可点击的时候需要重新的方法
            @Override
            public int getViewHorizontalDragRange(View child) {
                return getMeasuredWidth() - firstView.getMeasuredWidth();
            }

            // 当松手之后的回调
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                // when release let it go back of the init position
                int secondLeft = secondView.getLeft();
                int middle = (firstView.getLeft() + firstView.getRight()) / 2;
                LogUtils.e("secondLeft = " + secondLeft + " menuRight = "
                        + firstView.getRight() + " menuL = " + firstView.getLeft());
                if (secondLeft > middle) {
                    // open
                    helper.smoothSlideViewTo(releasedChild, firstView.getRight(), firstView.getTop());
                    ViewCompat.postInvalidateOnAnimation(get());
                } else {
                    // close
                    helper.smoothSlideViewTo(releasedChild, firstView.getLeft(), firstView.getTop());
                    ViewCompat.postInvalidateOnAnimation(get());
                }
            }
        });
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() != 2) {
            throw new RuntimeException("I had two children,where they are?");
        }
        firstView = getChildAt(0);
        firstView.setVisibility(VISIBLE);
        secondView = getChildAt(1);
        secondView.setVisibility(VISIBLE);
    }

    @Override
    public void computeScroll() {
        if (helper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        helper.processTouchEvent(event);
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return helper.shouldInterceptTouchEvent(ev);
    }
}
  • 简单介绍一下getViewHorizontalDragRange(View child)方法:
// 子View 可点击的时候需要重新的方法
@Override
 public int getViewHorizontalDragRange(View child) {
     return getMeasuredWidth() - firstView.getMeasuredWidth();
 }

这个方法,在子View可点击的时候需要重写。返回值>0,才可以拖动。

  • 还有这个方法clampViewPositionHorizontal(View child, int left, int dx)
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
    final int leftBound = firstView.getLeft(); // MainView侧滑的起点
    final int rightBound = firstView.getMeasuredWidth() - leftBound + 10; // 终点
    final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
    LogUtils.e("newL = " + newLeft + " rb = " + rightBound);
    return newLeft;
}

如果只是需要滑动效果,直接返回left即可。但是这里为了搞侧滑效果。所以,是希望她的滑动范围是MenuView的宽度。而int newLeft = Math.min(Math.max(left, leftBound), rightBound);这句代码的作用就是,如果left在指定的范围内,就返回left,否则就返回边界值。

  • 更多的关于ViewDragHelper的介绍,我就不介绍了。上面给出的链接都有详细的解释。
  • 好了,这样子,一个简单的侧滑效果就实现了,总体不到120行代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值