现在流行的app中都存在大量的滑动操作,但是一直没有去研究过,实在是不应该,正好这本书有讲解,就参考本书学习一下

  • 滑动产生的原因
  • 如何实现、处理滑动效果

1 . 滑动产生的原因

滑动一个View,本质上来说就是移动一个View。改变其当前所处位置,它的原理与动画效果非常相似,都是通过不断改变View的坐标来实现这一效果。所以,要实现View的滑动,就必须监听用户的触摸事件,从而实现View跟随用户触摸的滑动而滑动。

1.1 坐标系

如下图所示:

1.2 常见的获取坐标方法

2 .实现滑动的7中方法

要实现的效果:让自定义View随着手指在屏幕上的滑动而滑动

  • layout()方法
public class DragViewLayout extends View {    private int lastX;    private int lastY;    public DragViewLayout(Context context) {        super(context);    }    public DragViewLayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    public DragViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action){            case MotionEvent.ACTION_DOWN:                lastX = x;                lastY = y;                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - lastX;                int offsetY = y-lastY;                layout(getLeft()+offsetX,getTop()+offsetY,getRight()+offsetX,getBottom()+offsetY);                break;            case MotionEvent.ACTION_UP:                break;            default:                break;        }        return true;    }}
  • offsetLeftAndrRight()与offsetTopAndBottom()
public class DragViewOffset extends View {    private int lastX;    private int lastY;    public DragViewOffset(Context context) {        super(context);    }    public DragViewOffset(Context context, AttributeSet attrs) {        super(context, attrs);    }    public DragViewOffset(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action){            case MotionEvent.ACTION_DOWN:                lastX = x;                lastY = y;                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - lastX;                int offsetY = y-lastY;                offsetLeftAndRight(offsetX);                offsetTopAndBottom(offsetY);                break;            case MotionEvent.ACTION_UP:                break;            default:                break;        }        return true;    }}
  • LayoutParams
public class DragViewMargin extends View {    private int lastX;    private int lastY;    private ViewGroup.MarginLayoutParams params;    public DragViewMargin(Context context) {        super(context);    }    public DragViewMargin(Context context, AttributeSet attrs) {        super(context, attrs);    }    public DragViewMargin(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action){            case MotionEvent.ACTION_DOWN:                lastX = x;                lastY = y;                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - lastX;                int offsetY = y-lastY;                params = (ViewGroup.MarginLayoutParams) getLayoutParams();                params.leftMargin = getLeft()+offsetX;                params.topMargin = getTop()+offsetY;                setLayoutParams(params);                break;            case MotionEvent.ACTION_UP:                break;            default:                break;        }        return true;    }}
  • scrollTo 与scrollby,注意参考系的不同
/** * 如果是View使用Scrollby,移动的是view的内容,TextView,content是他的文本,ImageView,content是他的drawable * 如果是ViewGroup,移动的是所有子View */public class DragViewScrollBy extends View {    private int lastX;    private int lastY;    private ViewGroup.MarginLayoutParams params;    public DragViewScrollBy(Context context) {        super(context);    }    public DragViewScrollBy(Context context, AttributeSet attrs) {        super(context, attrs);    }    public DragViewScrollBy(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action) {            case MotionEvent.ACTION_DOWN:                lastX = x;                lastY = y;                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - lastX;                int offsetY = y - lastY;                //此处,是用-offset                ((ViewGroup) getParent()).scrollBy(-offsetX, -offsetY);                break;            case MotionEvent.ACTION_UP:                break;            default:                break;        }        return true;    }}
  • Scroller,实现平滑移动效果
/** * Created by acer on 2015/11/5. * 松开手指,回到原位置 * */public class DragViewScroller extends View {    private int lastX;    private int lastY;    private Scroller mscroller;    public DragViewScroller(Context context) {        super(context);        init(context);    }    public DragViewScroller(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public DragViewScroller(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    private void init(Context context) {        mscroller = new Scroller(context);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action) {            case MotionEvent.ACTION_DOWN:                lastX = x;                lastY = y;                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - lastX;                int offsetY = y - lastY;                ((View) getParent()).scrollBy(-offsetX, -offsetY);                break;            case MotionEvent.ACTION_UP:            //手指离开,开始滑动回原位置                View viewGroup = (View) getParent();                mscroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY());                invalidate();                break;            default:                break;        }        return true;    }    /** *computeScroll()方法不会自动调用, *只能通过invalidate()---draw()--computeScroll()来间接调用 * */    @Override    public void computeScroll() {        if (mscroller.computeScrollOffset()) {            ((View) getParent()).scrollTo(mscroller.getCurrX(), mscroller.getCurrY());            //通过重绘,不断调用computeScrol            invalidate();        }    }}
  • ViewGragHelper 强大的滑动控制类,实现各种不同的滑动,拖放需求
public class LearnViewDragHelper extends FrameLayout {    private ViewDragHelper mHelper;    private View mMenuView;    private View mMainView;    private int mWidth;    public LearnViewDragHelper(Context context) {        super(context);        init();    }    public LearnViewDragHelper(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public LearnViewDragHelper(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public LearnViewDragHelper(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init();    }    /** * 加载布局文件完成后调用 */    @Override    public void onFinishInflate(){        super.onFinishInflate();        mMenuView = getChildAt(0);        mMainView = getChildAt(1);    }    @Override    public void onSizeChanged(int w,int h,int oldw,int oldh){        super.onSizeChanged(w, h, oldw, oldh);        mWidth = mMenuView.getMeasuredWidth();    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return mHelper.shouldInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        //将触摸事件传递给ViewDragHelper,此操作必不可少        mHelper.processTouchEvent(event);        return true;    }    private void init() {        mHelper = ViewDragHelper.create(this, callback);    }    /** * 核心回調 **/    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {        /** * 开始检测触摸事件 * @param child * @param pointerId * @return */        @Override        public boolean tryCaptureView(View child, int pointerId) {            //如果当前触摸的child是mMainView时开始检测            return mMainView==child;        }        /** * 用户触摸到View后回调 * @param capturedChild * @param activePointerId */        @Override        public void onViewCaptured(View capturedChild, int activePointerId) {            super.onViewCaptured(capturedChild, activePointerId);        }        /** * view拖拽状态改变时回调 * @param state */        @Override        public void onViewDragStateChanged(int state) {            super.onViewDragStateChanged(state);        }        /** * view position改变时回调,常用于更改scale进行缩放等效果 * @param changedView * @param left * @param top * @param dx * @param dy */        @Override        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {            super.onViewPositionChanged(changedView, left, top, dx, dy);        }        /** * * 通常情况下,只需要返回top 和 left即可,但是当需要更加精确的计算padding等属性的时候,就需要对left进行一些处理,并返回合适大小的值 * */        /** * 水平方向滑动 * @param child * @param left 在水平方向child移动的距离 * @param dx 较前一次的增量 * @return 默认返回0 */        @Override        public int clampViewPositionHorizontal(View child, int left, int dx) {            return left;        }        /** * 竖直方向滑动 * @param child * @param top 在竖直方向child移动的距离 * @param dy 较前一次移动的距离 * @return 默认返回0 */        @Override        public int clampViewPositionVertical(View child, int top, int dy) {            return super.clampViewPositionVertical(child,top,dy);        }        /** * 拖动结束后调用 * @param releasedChild * @param xvel * @param yvel */        @Override        public void onViewReleased(View releasedChild, float xvel, float yvel) {            super.onViewReleased(releasedChild, xvel, yvel);            //手指抬起后,缓慢移动到指定位置            if(mMainView.getLeft()<500){                //关闭菜单,相当于Scroller.startScroll                mHelper.smoothSlideViewTo(mMainView,0,0);                ViewCompat.postInvalidateOnAnimation(LearnViewDragHelper.this);            }else{                //打开菜单                mHelper.smoothSlideViewTo(mMainView,300,0);/** *Cause an invalidate to happen on the next animation time *step, typically the next display frame * */                ViewCompat.postInvalidateOnAnimation(LearnViewDragHelper.this);            }        }    };    /** * Move the captured settling view by the appropriate amount for the current time. * If <code>continueSettling</code> returns true, the caller should call it again * on the next frame to continue. * * @param deferCallbacks true if state callbacks should be deferred via posted message. * Set this to true if you are calling this method from * {@link android.view.View#computeScroll()} or similar methods * invoked as part of layout or drawing. * @return true if settle is still in progress */    @Override    public void computeScroll() {        if (mHelper.continueSettling(true)) {            ViewCompat.postInvalidateOnAnimation(this);        }    }}

滑动效果图如下:

DragViewHelper效果图如下:

更多相关文章

  1. Android中AES加密解密。解决密文不唯一、解密不出明文问题
  2. (4.2.2.2)【android开源工具】【Android(安卓)UI设计与开发】第17
  3. Android调用系统安装程序打开本地文件(包括 Android7.0以上)
  4. 个人信息界面(二)
  5. Android(安卓)NDK 调用Skia进行底层绘图
  6. Android的简单应用(三)——为你的程序添加监听器
  7. Unity与Android交互方案优化版
  8. Android中Activity生命周期说明及使用
  9. Android(安卓)4.1性能分析的一般步骤(二)

随机推荐

  1. 程序员挑战高薪,你必须会的十大面试题《一
  2. adb命令执行java代码
  3. android 自定义图形之层叠样式 [layer-li
  4. android Api Demos
  5. location of the android sdk has not be
  6. 如何用Android(安卓)源码生成APK签名文件
  7. Android 4.03 编译系统------lunch
  8. Android:RecyclerView中Item的VideoView预
  9. Android系统的由来
  10. TextureView+MediaPlayer实现在线短视频