一:滑动的产生原因

滑动一个View原理:就是通过不断的改变View的坐标。
实现View的滑动,必须监听用户触摸的事件,根据触摸传入的坐标,动态的改变View的坐标,从而实现滑动
Android的坐标系:Android中屏幕的最左上端的点就是原点,向右就是X坐标轴的正方向,向下就是Y坐标轴的正方向
系统提供的getLocationOnScreen(intlocation[])方法获取Android坐标系中位置 触控事件中的getRawX 和getRawY方法实 现同样效果
视图坐标系:相对于Android坐标系,视图坐标系主要描述子View在父 View中的位置,将父视图 左上角作为坐标原点。触控事件中getX getY可以获取View的视图坐标系
触控事件:
常用到的:单点触摸、单点触摸离开屏幕、触摸点移动

public static final int ACTION_DOWN             = 0;public static final int ACTION_UP               = 1;public static final int ACTION_MOVE             = 2;

通常会在onTouchEvent(MotionEvent event)中通过event.getAction()方法获取触控事件的类型。
常用获取坐标的方法:
(1)View提供的获取坐标的方法
getTop:获取当前View自身的顶边到父布局顶边的距离
getLeft:获取当前View自身的左边到父布局左边的距离
getRight:获取当前View自身的右边到父布局右边的距离
getBottom:获取当前View自身的底边到父布局底边的距离
(2)触控事件MotionEvent中提供的方法
getX:视图坐标 点击事件到控件左边的距离
getY:视图坐标
getRawX:Android坐标 点击事件距离屏幕左端的距离
getRawY:Android坐标

二.实现滑动的七种方法

第一种:layout方法
采用getX,getY

// 视图坐标方式@Overridepublic boolean onTouchEvent(MotionEvent event) {//获取触控点的坐标int x = (int) event.getX();    int y = (int) event.getY();    switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 记录触摸点坐标lastX = x;lastY = y;            break;        case MotionEvent.ACTION_MOVE:// 计算偏移量int offsetX = x - lastX;            int offsetY = y - lastY;// 在当前left、top、right、bottom的基础上加上偏移量layout(getLeft() + offsetX,getTop() + offsetY,getRight() + offsetX,getBottom() + offsetY);//同时对left和right进行偏移           // offsetLeftAndRight(offsetX);            //同时对top还有bottom进行偏移           // offsetTopAndBottom(offsetY);break;}return true;}

采用getRawX getRawY

// 绝对坐标方式@Overridepublic boolean onTouchEvent(MotionEvent event) {int rawX = (int) (event.getRawX());        int rawY = (int) (event.getRawY());        switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 记录触摸点坐标lastX = rawX;lastY = rawY;                break;            case MotionEvent.ACTION_MOVE:// 计算偏移量int offsetX = rawX - lastX;                int offsetY = rawY - lastY;// 在当前left、top、right、bottom的基础上加上偏移量layout(getLeft() + offsetX,getTop() + offsetY,getRight() + offsetX,getBottom() + offsetY);// 重新设置初始坐标lastX = rawX;lastY = rawY;                break;}return true;}}

执行完Action_Move后这里需要重新设置初始坐标,具体原因尚未搞懂、
第二种:offsetLeftAndRight() offsetTopAndBottom()方法 见第一段代码
第三种 LayoutParams

@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();        int y = (int) event.getY();        switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 记录触摸点坐标lastX = (int) event.getX();lastY = (int) event.getY();                break;            case MotionEvent.ACTION_MOVE:// 计算偏移量int offsetX = x - lastX;                int offsetY = y - lastY;ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();//根据父布局类型的不同选择 这里父布局是LinearLayout// LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();layoutParams.leftMargin = getLeft() + offsetX;layoutParams.topMargin = getTop() + offsetY;setLayoutParams(layoutParams);                break;}return true;}

LayoutParams保存一个View的布局参数,因此可以改变LayoutParams来实现View位置改变
使用此方法的前提是 此View必须有一个父布局
第四种 scrollTo scrollBy
scrollTo(x,y)移动到坐标是x,y的位置 scrollBy(x,y)表示移动的增量

这种方法需要注意两点:
第一点:这两种方法移动的是View的content,在ViewGroup中移动的是子View
第二点:将scrollBy中的参数设为正,那么content将向坐标轴负方向移动;同理,将scrollBy中的参数设为负,那么content将向坐标轴正方向移动

((View) getParent()).scrollBy(-offsetX,-offsetY);

第五种 Scroller
使用scrollTo和scrollBy方法,子View的平移是瞬时的,采用Scroller类可以实现平滑移动,而不是瞬时移动
( 1 )初始化 Scroller
( 2 )重写computeScroll方法,实现模拟滑动
(3)startScroll开启模拟过程

private void initView() {    setBackgroundColor(Color.BLUE);mScroller=new Scroller(getContext());}@Overridepublic void computeScroll() {super.computeScroll();//computeScrollOffset方法判别是否完成整个滑动,未完成返回trueif(mScroller.computeScrollOffset()){//.getCurrX() getCurrY()获取当前的滑动坐标((View)getParent()).scrollTo(  mScroller.getCurrX(),mScroller.getCurrY());//通过重绘(draw)不断调用computeScrolL完成滑动invalidate();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {int x= (int)event.getX();    int y=(int)event.getY();    switch(event.getAction()){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;}return true;}

第六种 属性动画
第七种 ViewDragHelper
通过使用
ViewDragHelper 基本可以实现各种不同的滑动,拖放要求
(1)初始化ViewDragHelper
(2)拦截事件
(3)处理computeScroll
(4)处理回调CallBack

public class DragViewGroup extends FrameLayout {private ViewDragHelper mViewDragHelper;    private View mMenuView;    private View mMainView;    private int mWidth;    public DragViewGroup(Context context) {super(context);initView();}public DragViewGroup(Context context, AttributeSet attrs) {super(context, attrs);initView();}public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView();}@Overrideprotected void onFinishInflate() {super.onFinishInflate();mMenuView=getChildAt(0);mMainView=getChildAt(1);}@Overrideprotected 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 mViewDragHelper.shouldInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {mViewDragHelper.processTouchEvent(event);        return true;}private void initView(){//初始化ViewDragHelper 第一个参数是要监听的View,通常是ViewGroup        //第二个参数是一个CallaBack的回调 ,这个回调是整个ViewDragHelper的逻辑核心mViewDragHelper=ViewDragHelper.create(this,callback);}private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {@Override//通过此方法确定要移动的子Viewpublic boolean tryCaptureView(View child, int pointerId) {return mMainView==child;}@Override//下面两种方法分别对应垂直和水平移动      //其中top 就是垂直方向上移动的距离 left就是水平移动的距离public int clampViewPositionVertical(View child, int top, int dy) {return 0;}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {return left;}@Override//这个方法用于实现收支离开屏幕时的操作public void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);          if(mMainView.getLeft()<500){//关闭菜单mViewDragHelper.smoothSlideViewTo(mMainView,0,0);ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);}else{mViewDragHelper.smoothSlideViewTo(mMainView,300,0);ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);}      }  };@Overridepublic void computeScroll() {if(mViewDragHelper.continueSettling(true)){            ViewCompat.postInvalidateOnAnimation(this);}    }}

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android智能指针SP WP使用方法介绍
  5. Android地图应用新视界--mapbox的常用功能封装工具类
  6. android与javascript交互调用
  7. Android和js、H5进行交互数据(面试必问)
  8. 写给Android(安卓)App开发人员看的Android底层知识(1)
  9. 在android屏幕上 上 下 左 右 四个方向移动法拉利(Image)

随机推荐

  1. Dialog的使用
  2. 通过反射获取Android通知栏高度
  3. android 重启
  4. Android ButterKnife 使用方法总结
  5. 自定义控件:滑动开关按钮
  6. xamarin.forms 使用ZXing扫描二维码
  7. Android懒人框架Android annotation
  8. Android(安卓)Camera API使用指南
  9. 第三方社交网站分享(微信,新浪微博)
  10. Android(安卓)拍照7.0适配(源码)