Android ViewDragHelper Demo

本文介绍了一个自定义的MyViewGroup组件,该组件利用ViewDragHelper实现了左右上下菜单的拖拽效果。文章详细展示了如何通过重写ViewDragHelper.Callback接口来控制子视图的位置,并提供了如何设置触摸拦截、拖拽范围及最终位置等关键代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.lc.mywidget;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

public class MyViewGroup extends RelativeLayout {
    private View mView1;//left
    private View mView2;//right
    private View mView3;//top
    private View mView4;//bottom
    private ViewDragHelper mViewDragHelper;
    private float mLeftMenuOnScreen = 0f;//显示百分比
    private float mRightMenuOnScreen=0f;
    private int symbol = 0; // 0 都不显示 -1 显示左菜单 1 右边菜单 -2 顶部菜单 2 底部菜单
    private float widthPercent =0.5f;
    private float parentWidth =0;
    private float parentHeight = 0;
    private int actionBarHeight = 96;
    private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //设置拦截的view
           /* boolean capture = false;
            if(mView1 == child || mView2 == child || mView4 == child || mView3 == child){
                capture = true;
                if(mView2 == child){
                    symbol = 1;
                }else if(mView1 == child){
                    symbol =-1;
                }else if(mView3 == child){
                    symbol = -2;
                }else{
                    symbol = 2;
                }
            }
            Log.d("lcc","capture view"+capture+ " symbol = " + symbol);*/
            return true;
        }

    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
        //通过判断水平方向该view的left取值范围,设置值
        Log.d("lcc","clamp horizontal "+left);
        int newLeft = 0;
        if(symbol == -1) {
            newLeft = Math.max(-child.getWidth(), Math.min(left, 0));
        }else if(symbol ==1){
            newLeft =  Math.min((int)parentWidth,Math.max(left,(int)parentWidth-child.getWidth()));
        }
        Log.d("lcc","symbol = "+ symbol+" newLeft="+newLeft);
        return newLeft;
    }

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        //通过判断垂直方向该view的top取值范围,设置值
        int newTop = 0;
        if(symbol == -2){
            newTop = Math.max(-child.getHeight(),Math.min(top,0));
        }else if(symbol == 2){
            newTop = Math.min((int)parentHeight,Math.max(top,(int)parentHeight-child.getHeight()));
        }
        Log.d("lcc","clamp vertical " + newTop);
        return newTop;
    }

    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
        //当手指离开屏幕时,根据当前运行速度和已显示所占的百分比设置最终状态(显示或隐藏)
        Log.d("lcc","onViewReleased "+releasedChild.getLeft()+ " symbol = "+ symbol);
        super.onViewReleased(releasedChild, xvel, yvel);
        final int childWidth = releasedChild.getWidth();
        final int childHeight = releasedChild.getHeight();
        float offset = 0;
        if(symbol == -1) {
            offset = (childWidth + releasedChild.getLeft()) * 1.0f / childWidth;
            mViewDragHelper.settleCapturedViewAt(xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth, releasedChild.getTop());
        }else if(symbol == 1){
            offset = (parentWidth-releasedChild.getLeft()) * 1.0f / childWidth;
            mViewDragHelper.settleCapturedViewAt(xvel < 0 || xvel == 0 && offset > 0.5f ? (int)(parentWidth-childWidth) : (int)parentWidth, releasedChild.getTop());
        }else if(symbol == -2){
            offset = (childHeight + releasedChild.getTop()) * 1.0f / childHeight;
            mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(),yvel > 0 || yvel == 0 && offset > 0.5f ? 0 : -childHeight);
        }else{
            offset = (parentHeight-actionBarHeight- releasedChild.getTop()) * 1.0f / childHeight;
            mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(),yvel < 0 || yvel == 0 && offset > 0.5f ? (int)(parentHeight-childHeight-actionBarHeight) : (int)parentHeight);
        }
        invalidate();
    }

    @Override
    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
        Log.d("lcc"," onViewPositionChanged symbol  = " + symbol);
        final int childWidth = changedView.getWidth();
        final int childHeight = changedView.getHeight();
        float offset = 0;
        if(symbol == -1){
            offset = (float) (childWidth + left) / childWidth;
            mLeftMenuOnScreen = offset;
        }else if(symbol == 1){
            offset = (parentWidth-left) / childWidth;
            mRightMenuOnScreen = offset;
        }else if(symbol == -2){
            offset = (childHeight+top)/childHeight;

        }else{
            offset = (parentHeight-top)/childHeight;
        }

        //offset can callback here
        changedView.setVisibility(offset == 0 ? View.INVISIBLE : View.VISIBLE);
        invalidate();
    }

    @Override
    public int getViewHorizontalDragRange(View child) {
        return child.getWidth();
    }

    @Override
    public int getViewVerticalDragRange(View child) {
        return 0;
    }

    @Override
    public void onEdgeDragStarted(int edgeFlags, int pointerId) {
        if(edgeFlags == ViewDragHelper.EDGE_LEFT) {
            Log.d("lcc","edge left");
            mViewDragHelper.captureChildView(mView1, pointerId);
            symbol = -1;
        }else if(edgeFlags == ViewDragHelper.EDGE_RIGHT){
            Log.d("lcc","edge right");
            mViewDragHelper.captureChildView(mView2,pointerId);
            symbol = 1;
        }else if(edgeFlags == ViewDragHelper.EDGE_TOP){
            Log.d("lcc","edge top");
            mViewDragHelper.captureChildView(mView3,pointerId);
            symbol = -2;
        }else{
            Log.d("lcc","edge bottom");
            mViewDragHelper.captureChildView(mView4,pointerId);
            symbol = 2;
        }
    }
};
public MyViewGroup(Context context, AttributeSet attrs) {
    super(context, attrs);
    parentWidth = context.getResources().getDisplayMetrics().widthPixels;
    mViewDragHelper = ViewDragHelper.create(this,mCallback);
    mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL );
    //设置minVelocity
    mViewDragHelper.setMinVelocity(400*getResources().getDisplayMetrics().density);
    DisplayMetrics metircs= getResources().getDisplayMetrics();
    parentWidth = metircs.widthPixels;
    parentHeight = metircs.heightPixels;
    actionBarHeight = getActionBarHeight();
    Log.d("lcc"," parentWidth = "+ parentWidth);
}

public MyViewGroup(Context context) {
    super(context);
    mViewDragHelper = ViewDragHelper.create(this,mCallback);
    mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);

    //设置minVelocity
    mViewDragHelper.setMinVelocity(400*getResources().getDisplayMetrics().density);
    DisplayMetrics metircs= getResources().getDisplayMetrics();
    parentWidth = metircs.widthPixels;
    parentHeight = metircs.heightPixels;
    actionBarHeight = getActionBarHeight();
    Log.d("lcc"," parentWidth = "+ parentWidth);
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    mView1 = getChildAt(0);
    mView2 = getChildAt(1);
    mView3 = getChildAt(2);
    mView4 = getChildAt(3);

}

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

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean intercepte = mViewDragHelper.shouldInterceptTouchEvent(ev);
    Log.d("lcc","intercept="+intercepte);
    return intercepte;
}

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

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    mView1 = getChildAt(0);
    mView2 = getChildAt(1);
    mView3 = getChildAt(2);
    mView4 = getChildAt(3);

    MarginLayoutParams mp = (MarginLayoutParams) mView1.getLayoutParams();
    int view1Width = (int) (mView1.getMeasuredWidth()*widthPercent);
    int left = (int) (-view1Width+view1Width * mLeftMenuOnScreen);
    mView1.layout(left,mp.topMargin,left+view1Width,mp.topMargin+mView1.getMeasuredHeight());
    Log.d("lcc","myView1 left=" + left + " right = " + (left+view1Width));

    mp = (MarginLayoutParams) mView2.getLayoutParams();
    int view2Width = (int) (mView2.getMeasuredWidth()*widthPercent);

    int left2 = (int) parentWidth;
    mView2.layout(left2,mp.topMargin,left2+view2Width,mView2.getMeasuredHeight()+mp.topMargin);
    Log.d("lcc","myView2 left=" + left2 + " right = " + (left2+view2Width));

    mp = (MarginLayoutParams) mView3.getLayoutParams();
    int viewHeight = (int) (mView3.getMeasuredHeight()*widthPercent);
    mView3.layout(mp.leftMargin,mp.topMargin-viewHeight,mp.leftMargin+mView3.getMeasuredWidth(),mp.topMargin);
    Log.d("lcc","myView3 top=" + (mp.topMargin-viewHeight) + " bottom = " + mp.topMargin);

    mp = (MarginLayoutParams) mView4.getLayoutParams();
    int viewHeight2 = (int) (mView4.getMeasuredHeight()*widthPercent);
    mView4.layout(mp.leftMargin,(int)(parentHeight+mp.topMargin-actionBarHeight),mp.leftMargin+mView4.getMeasuredWidth(),(int) (parentHeight+viewHeight2+mp.topMargin-actionBarHeight));
    Log.d("lcc","myView4 top=" + (mp.topMargin+parentHeight) + " bottom = " + mp.topMargin);
}
public int getActionBarHeight(){
    TypedValue tv = new TypedValue();
    if (getContext().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
        int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getContext().getResources().getDisplayMetrics());
        Log.d("lcc","actionBarHeight = " + actionBarHeight);
        return actionBarHeight;
    }
   else{
        Log.d("lcc","actionBarHeight = " + 0);
        return 0;
    }
}
}

上述demo是对其他博主demo的一个扩展,原文链接:http://blog.youkuaiyun.com/lmj623565791/article/details/47396187

练习时发现ViewDragHelper在多次调用captureChildView()方法后只会对最后一个view的行为进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值