滑动一个View,本质上就是移动一个View的位置,它的实现与动画的实现非常相似,通过不断的改变View的位置来实现这一效果。所以,如果要实现这一效果,必定要监听用户的触摸事件。在前面我们已经深入分析了触摸事件的传递和分发机制。今天在这里同样还需要使用到MotionEvent。
在实现滑动之前,我们先来熟悉一下Android中的坐标系。
在Android中,将屏幕的左上角的顶点作为Android坐标系的原点,从这个点向右是X轴正方向,从这个点向下是Y轴正方向。如图,
另外不得不提的是,在触控事件中使用的getRawX()和getRawY()方法获取的坐标是Android坐标系中的坐标。使用getX()和getY()方法获得的是视图坐标系的坐标,下面用一张简单的图解释什么叫视图坐标系。
好了,基础的知识介绍完了,现在说明一下实现View滑动的思想,当触摸View时,记录下当前触摸的坐标,当手指移动时,记录下移动后的触摸点的坐标,从而获得相对于上一次记录的坐标点的偏移量,并通过偏移量来修改View的坐标,从而实现了View的滑动过程。
首先,很容易想到的,也是在View的绘制过程中,非常重要的一个步骤--View的布局(OnLayout),通过给View重新布局从而实现滑动的效果。
下面来看一下具体的实现:
1.通过基本的layout方法,就向上面我们提到的,在View进行绘制时,会调用OnLayout()方法来设置显示的位置,同时可以修改View的left,top,right,bottom四个属性来控制View的坐标。
先上代码:
@Override public 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; //使用layout重新布局 layout(getLeft()+offsetX,getTop()+offsetY,getRight()+offsetX,getBottom()+offsetY); lastX=rawX; lastY=rawY; break; } return super.onTouchEvent(event); }上面使用的是Android坐标系来进行对比的。每次移动后,View都会调用Layout方法来对自己重新布局,从而达到View的移动效果。
2.offsetLeftAndRight与offsetTopAndBottom()
这个方法相当于系统提供的一个对左右,上下移动的API的封装,该方法和上面layout方法的实现原理相,但是使用简单。
//同时对left和right进行偏移 offsetLeftAndRight(offsetX); //同时对top和bottom进行偏移 offsetTopAndBottom(offsetY);
LayoutParams保存了一个View的布局参数,所以可以在程序中通过改变LayoutParams来动态修改一个布局的位置参数,从而实现改变View位置的效果。
实现过程如下,在程序中通过getLayoutParams()来获取要移动的View的LayoutParams,然后获取到偏移量之后,在通过setLayoutParams来改变其LayoutParams。
代码如下:
LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams(); layoutParams.leftMargin=getLeft()+offsetX; layoutParams.topMargin=getTop()+offsetY; setLayoutParams(layoutParams);
相信大家也都注意到了,上面的代码不是固定的,而是会因为父布局的类型不同而设置不同的类型,为了代码的灵活度,这里推荐使用ViewGroup.MarginLayoutParams来实现上面的代码,因为不需要考虑父布局的类型,当然它们的本质都是一样的。
后面的文章将会给大家讲解一下其他的View滑动实现方法,ScrollTo,ScrollBy,属性动画等方式。