滑动效果是如何产生的?

滑动一个View从本质上来说就是移动一个View,改变其当前的坐标。所以,想要滑动一个View,就必须监听该View的触摸事件,并且根据事件的坐标,不断的改变View的坐标从而实现View的滑动。

Android中的坐标体系

Android中的坐标体系分为两种:

  1. Android坐标系
  2. 视图坐标系

Android坐标系

Android坐标系

从图中我们可以看的出来在Android坐标系中以屏幕的左上方作为坐标系的原点,从原点向右为X轴的正方向,向下为Y轴的正方向。在触控事件中使用getRawX()、getRawY()来获得Android坐标系的坐标

视图坐标系

视图坐标系

视图坐标系主要描述的是该View和该View在父视图中的位置关系,和Android坐标系一样,也是以原点右方为X正方向,以原点下方为Y轴正方向,不过这里不是以屏幕的左上角为原点,而是以父视图的左上角为原点。在触控事件中使用getX()、getY()来获得视图坐标系的坐标

触控事件

在上一篇文章中我们使用到了MotionEvent,这个就是触控事件的封装,首先看一下MotionEvent中封装的事件常量

  • public static final int ACTION_DOWN = 0; //单点触摸按下动作
  • public static final int ACTION_UP = 1; //单点触摸离开动作
  • public static final int ACTION_MOVE = 2; //单点触摸移动动作
  • public static final int ACTION_CANCEL = 3; //触摸动作取消
  • public staiic final int ACTION_OUTSIDE = 4; //触摸动作超出边界
  • public static final int ACTION_POINTER_DOWN = 5; //多点触摸按下动作
  • public static final int ACTION_POINTER_UP = 6; 多点离开动作

通常情况下我们会在onTouchEvent(MotionEvent event)方法中通过event.getAction()来获取触控事件的类型。知道Android中的坐标系和触控事件之后我们就可以来实现View的滑动了


滑动实现

实现滑动有好多种方法,但是其思想都是一样的。当触摸到View时,记录当前触摸点的坐标,然后当手指移动时,获取到相对于前一个点的偏移量,这样我们就可以通过这个偏移量来进行修改View的坐标,这样不断的重复,就能实现View的滑动

举个例子

我们自定义一个View,让他来跟随我们手指的移动来移动,如图:

  • layout方法

我们知道在View进行绘制的时候会通过onLayout()方法来设置View的显示位置,这里我们通过修改View的left, top, right, bottom四个值来控制View的坐标

public 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;            //在当前位置基础加上偏移量            layout(                    getLeft() + offsetX,                    getTop() + offsetY,                    getRight() + offsetX,                    getBottom() + offsetY            );            break;    }    return true;}

  • offsetLeftAndRight()和offsetTopAndBottom

这个方法就是相当于系统提供的一个对左右、上下移动的API的封装,计算好偏移量后,调用方法即可:

offsetLeftAndRight(offsetX);offsetTopAndBottom(offsetY);

  • LayoutParams

LayoutParams保存了View的布局参数,所以我们可以改变LayoutParams来动态的改变布局的位置来达到滑动的效果。在程序中使用getLayoutParams()来获取当前View的LayoutParams,这里就和上面一样,获取到偏移量后通过setLayoutParams来设置该View的LayoutParams:

RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();params.leftMargin = getLeft() + offsetX;params.topMargin = getTop() + offsetY;setLayoutParams(params);

需要注意一点,通过getLayoutParams()获取LayoutParams的时候,要根据View的父布局的类型来设置,当然前提还要有一个父布局。还有就是我们可以使用ViewGroup.MarginLayoutParams,这样就不用考虑父布局是什么了


  • scrollTo、scrollBy

在View中,系统还提供了scrollTo、scrollBy两种方式来改变一个View的位置。

其中scrollTo表示移动到一个具体的坐标点,scrollBy表示移动的偏移量,其实在scrollBy内部也是调用的scrollTo。

和前面的方式一样,获取到偏移量后调用scrollBy来移动view,可是当我们运行程序,拖动View,发现View并没有移动!这是因为scrollTo、scrollBy方法移动的是View的内容,如果在ViewGroup中使用scrollTo、scrollBy的滑,那么移动的就是View了,但是如果在View中使用,那么移动的将是View里面的内容,比如TextView,那么移动的就是文本了。

所以通过上面的分析,我们把代码改为如下:

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

再次运行程序,我们会发现动是动了,但是在乱动。因为这里我们其实是在相反的方向移动(这里由于篇幅限制,感兴趣的同学自行查找一下资料),我们把偏移量改为负的之后就会发现滑动正常了。


  • Scroller

首先来想一个场景:我们需要让一个Button向右面移动100个像素,如果我们用scrollTo/scrollBy的话,那么该View就会很突兀的移动到该点,没有过程,而Scroller则是可以实现平滑的过渡效果的

下面我们把上面跟随手指滑动的例子改一下,我们在松开手指后,View自动回到原点(屏幕左上角)。使用Scroller需要三个步骤

  1. 初始化
    • 通过构造方法即可 Scroller mScroller = new Scroller(context);
  2. 重写computeScroll()方法,实现滑动
  3. startScroll()开启滑动

代码如下:

        case MotionEvent.ACTION_UP:            View viewGroup = (View) getParent();            mScroller.startScroll(                    viewGroup.getScrollX(),                    viewGroup.getScrollY(),                    -viewGroup.getScrollX(),                    -viewGroup.getScrollY()            );            invalidate();            break;              ----------------------------------------------------------------                         @Overrid          public void computeScroll() {            super.computeScroll();            if (mScroller.computeScrollOffset()) {            ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            invalidate();    }}

当我们手指抬起来的时候开启Scroller滑动,获取到当前view的移动距离,然后我们把需要移动的偏移量设置为相反数就ok,最后调用invalidate来通知重绘,从而调用computeScroll()方法。运行程序如下:

现在就把这几种View的滑动都说完了,自己动手写一下,感触良多。


最后

爱生活,爱小丽,爱Android

更多相关文章

  1. [Android]ScrollView和ListView套用冲突的解决方法
  2. Android:GestureDetector手势识别类
  3. CouchDB降临Android
  4. Android(安卓)滑动效果入门篇(一)—— ViewFlipper
  5. Android滑动的实现
  6. Android(安卓)slidingmenu详细解释 滑动的优化
  7. Android在SDcard建文件夹(在Android中移动文件必用)
  8. Android小知识7
  9. Android屏蔽/禁止ViewPager左右滑动/滚动

随机推荐

  1. Android利用传感器实现微信摇一摇功能
  2. Android实现计时与倒计时(限时抢购)的几
  3. android利用http请求xml
  4. [Android新手学习笔记08]-如何让活动Acti
  5. android listview數據顯示優化
  6. Android组件Activity中的View绘画和动画(A
  7. Android动态化UI框架一、Virtualview-And
  8. Android网络服务开发之http编程
  9. Android中Bitmap, Drawable, Byte,ID之间
  10. 使用otta bus进行android组件通信