Android 坐标系和 MotionEvent 分析、滑动
1.Android坐标系
在Android中,屏幕最左上角的顶点作为Android坐标系的原点,这个点向左是X轴正方向,这个点向下是Y轴正方向。

系统提供了getLocationOnScreen(int location[])这样的方法来获得Android坐标系中中点的位置(即该图的左上角在Android坐标系中的坐标)。另外,触控事件中使用getRawX() 、getRawY()方法所获得的坐标同样是Android坐标系中的坐标。
2.视图坐标系
Android除了上面说的坐标系之外,还有一个视图坐标系,它描述了子视图在父视图中的位置关系。这两种坐标系并不矛盾也不复杂,他们的作用是相辅相成的,正方向的指向是相同的,只是原点的位置不再是Android坐标系中的屏幕最左上角,而是以父视图左上角为坐标原点。在触控事件中,通过getX()、getY()坐标就是视图坐标系中的坐标

3.触控事件—MotionEvent
触控事件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 static 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() 方法来获取触控事件的类型并通过switch-case方法来筛选,这代码的模式基本固定,如下:
@Overrride
public boolean onTouchEvent(MotionEvent event) {
// 获取当前输入点的X,Y坐标(视图坐标)
int x = (int) event.getX();
int y = (int) event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
// 处理输入的按下事件
break;
case MotionEvent.ACTION_MOVE:
// 处理输入的移动事件
break;
case MotionEvent.ACTION_UP:
// 处理输入的离开事件
break;
}
return true;
}
这个代码模板是不涉及多点操作的,基本上可以帮助完成常见的触控操作的监听。
下面图示可以帮助你了解测量时的API如何使用它们,并帮助对MotionEvent和Android坐标系有了一个比较清楚的认识。

4.七种滑动方法
(1).layout方法
简单的来说就是,记录触摸的初始值和偏移量,然后通过layout方法移动控件。
(2).offsetLeftAndRight()与offsetTopAndBottom()
这个是系统提供的一个对上下、左右移动的API的封装。当计算出来偏移量后,需要使用下面的代码就可以重新布局,效果和使用Layout一样,代码如下。
// 同时对left和right进行偏移
offsetLeftAndRight(offsetX);
// 同时对top和bottom进行偏移
offsetTopAndBottom(offsetY);
(3).LayoutParams
LayoutParams保存了一个View的布局参数。我们可以改变LayoutParams来动态修改一个布局的位置参数,从而来达到改变View位置的效果。我们可以很方便的在程序中使用getLayoutParams()来获取一个View的LayoutParams。获取到偏移量后就可以通过setLayoutParams()来改变其LayoutParams。不过,需要注意的是LayoutParams的类型问题,要根据父容器的类型来设置不同的类型的LayoutParams。如果不清楚父类容器是什么,可以使用ViewGroup.MarginLayoutParams。
(4).scrollTo 与 scrollBy
这两个方法是view提供的方法来改变一个View的位置,scrollTo(x,y)表示移动到一个具体的坐标点(x,y),而scrollBy(dx, dy)表示移动的增量为dx,dy。需要注意的是,在View上面执行这两个方法,移动的并不是View本身而是View的内容,如果在ViewGroup中使用scrollTo,scrollBy方法,那么移动的是所有的子View,如果在View中使用,那么移动的将是View的内容,例如TextView,内容就是它的文本,ImageView,内容就是它的drawable对象。
通过上面的分析,我们就应该知道为什么不能在View中使用这两个方法来拖动这个View了。那么我们就要在View所在的ViewGroup中来使用scrollBy方法,移动它的子View,代码如下所示:
((View) getParent.getScrollBy(offsetX, offsetY);
但是因为参考系的问题,在真正操作的时候,如果需要根据拖动来滑动,则需要做的事情就是在计算参数时需要做转负值操作:
int offsetX = x - lastX;
int offsetY = y - lastY;
((View)getParent.scrollBy(-offsetX, -offsetY);
通过查看下面的图就可以了解到为何要做这个处理。

(5).Scroller
Scroller类提供了自然过度动画来实现移动效果,即实现平滑移动的效果,而不再是瞬间完成的移动。下面我们会演示一下如何使用Scroller类实现平滑移动。需求是:子View跟随手指的滑动而滑动,但是在手指离开屏幕时,让子View平滑的移动到初始位置,即屏幕左上角。
使用Scroller类需要如下三个步骤:
- 初始化Scroll
首先要通过它的构造方法来创建一个Scroller对象:
// 初始化Scroller
mScroller = new Scroller(context);
- 重写computeScroll()方法,实现模拟滑动
下面我们需要重写computeScroll(),它是使用Scroller的核心,系统在绘制view的时候回在draw()方法中调用该方法。这个方法实际上就是使用的ScrollTo方法。再结合Scroller对象,帮助获取到当前的滚动值。我们可以通过不断地瞬间移动一个小的距离来实现整体上的平滑移动效果。computeScroll的代码可以利用如下模版代码来实现:
@Override
public void computeScroll() {
super.computeScroll();
// 判断Scroller是否执行完毕
if (mScroller.computeScrollOffset()) {
((View) getParent()).scrollTo(
mScroller.getCurrX(),
mScroller.getCurrY());
// 通过重绘来不断调用computeScroll
invalidate();
}
}
Scroller 类提供了computeScrollOffset()方法来判断是否完成了整个滑动,同时也提供了getCurrX(),getCurrY()方法来获得当前的滑动坐标。在上面的代码中,唯一需要注意的是invalidate()方法,因为只能在computeScroll()方法中获取模拟过程中的scrollX和scrollY坐标,但是computeScroll是不会自动调用的,只能通过invalidate() --》draw()--》computeScroll()来间接调用computeScroll方法,实现循环获取scrollX和scrollY的目的。当模拟过程结束后,scroll.computeScrollOffset()方法会返回fasle,从而中断循环,完成整个平滑移动过程。
- startScroll开启模拟过程
startScroll()方法具有两个重载方法:
public void startScroll(int startX, int startY, int dx, int dy) {
startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
}
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
}
在使用的时候,dx 和 dy的正负和上面scrollTo 与 scrollBy的方法的一样。代码如下:
case MotionEvent.ACTION_UP:
// 手指离开时,执行滑动过程
View viewGroup = ((View) getParent());
mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY());
invalidate();
break;
6.属性动画
这个目前不做过多的介绍。
7.ViewDragHelper
这个功能很强大,可以先看一下QQ的侧边栏滑动,然后再总结这块的内容。
Android 坐标系和 MotionEvent 分析、滑动的更多相关文章
- Android Scroll分析——滑动效果产生
相对于在Android2.x版本上出现的长按.点击事件的效果,不得不说,滑动操作具有更好的用户体验.因此,从Android 4.X版本开始,出现了更多滑动操作的效果.越来越多第三方应用模仿这样的效果, ...
- android中实现view可以滑动的六种方法
在android开发中,经常会遇到一个view需要它能够支持滑动的需求.今天就来总结实现其滑动的六种方法.其实每一种方法的 思路都是一样的,即:监听手势触摸的坐标来实现view坐标的变化,从而实现vi ...
- ViewPager源码分析——滑动切换页面处理过程
上周客户反馈Contacts快速滑动界面切换tab有明显卡顿,让优化. 自己验证又没发现卡顿现象,但总得给客户一个技术性的回复,于是看了一下ViewPager源码中处理滑动切换tab的过程. View ...
- Android UI效果实现——Activity滑动退出效果
更新说明: 1.在QQ网友北京-旭的提醒下,在SlideFrame的initilize方法中添加了focusable.focusableInTouch.clickable的状态设置,否则会导致部分情况 ...
- Android使用ViewFlipper实现左右滑动效果面
在我的博客中,上次是使用ViewPager实现左右滑动的效果的,请看文章:Android使用ViewPager实现左右滑动效果. 这次我来使用ViewFlipper实现这种效果,好了,先看看效果吧: ...
- android wifi ANR问题分析总结
android wifi ANR问题分析总结 1 看看main进程阻塞在那里? 2 调用关系的函数阻塞在那里? 3 最终阻塞函数的阻塞前的log以及状态
- 从Android系统出发,分析Android控件构架
从Android系统出发,分析Android控件构架 Android中所有的控件追溯到根源,就是View 和ViewGroup,相信这个大家都知道,但是大家也许会不太清楚它们之间的具体关系是什么,在A ...
- [转] Android实时抓包分析 : 善用adb调试桥
Android实时抓包分析 : 善用adb调试桥 谈到android网络抓包,很多人都能想到牛逼轰轰的神器tcpdump.方法就是在android机器上面安装tcpdump,然后通过-w参数把抓包 ...
- [置顶] Android开发之serviceManager分析
Android 开发之serviceManager分析 在Android系统中用到最多的通信机制就是Binder,Binder主要由Client.Server.ServiceManager和Binde ...
随机推荐
- apache安装mod_deflate配置支持gzip
apache 配置支持gzip apache使用gzip压缩能够大幅提高网站访问速度并节省网络流量,在网页响应头信息中可以判断是否支持压缩. HTTP/1.1 200 OK Date: Wed, 14 ...
- RocksDB笔记 - Compaction中的Iterator
Compaction中的Iterator 一般来说,Compaction的Input涉及两层数据的合并,对于涉及到的每一层数据: 如果是level-0,对level-0的每一个sstable文件建立一 ...
- visual studio 2005 常用按键
VS2005 实用快捷键,迅速提高代码编写效率! 代码快捷键 Ctrl+J / Ctrl+K,L 列出成员 Ctrl+Shift+空格键 / Ctrl+K,P 参数信息 Ctrl+ ...
- JQuery延时操作
JQuery通过setTimeout函数可以实现延时操作以完成在编程达到某些需要的效果. 使用方法如下: function doSomething() { alert("hello worl ...
- 关于MFC文本框输入内容的获取 与 设置文本框的内容
八月要开始做界面了<( ̄︶ ̄)/,然而目前只会用MFC╮(╯▽╰)╭ 好吧,言归正传,设置好文本框后,要获取用户输入的内容,可以用: GetDlgItemText() ; 这个函数有两个参数,第 ...
- Linux系统安装VMware tools
VMware tools还是挺有用的,在两个不同系统随意拖拽文件,甚至文字的复制粘贴,功能强大. 废话不多说... 虽然VMware tools的安装帮助文档写的不错但是实际操作中发现,...还是有坑 ...
- 萝卜白菜,给有所爱——C#和JAVA都会终将被时代淘汰
看到园子里又有一波试图掀起C#和JAVA的谁更好的争论,对于这些一直不断的争论,我觉得实在没有必要,黑格尔的存在即合理,中国的老古语说的萝卜白菜各有所爱,大家争论的再多其实卵用也没用,还不如趁着闲暇时 ...
- XMPP即时通信(基础)
使用第三方框架 XMPPFramework #import "ViewController.h" #import "XMPPFramework.h" @ ...
- LoadRunner事务/集合点/思考时间详解(转)
在LoadRunner的脚步编写中,有三个重要的概念:事务.集合点.思考时间. 一.事务: 事务又称为Transaction,我们为了衡量某个action的性能,需要在action的开始和结束位置插入 ...
- nginx.conf各参数的意义
搬运+翻译至 http://qiita.com/syou007/items/3e2d410bbe65a364b603 /etc/nginx/nginx.conf 记录各个参数的意义 user user ...