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 ...
随机推荐
- Web系统大规模并发——电商秒杀与抢购 【转】
电商的秒杀和抢购,对我们来说,都不是一个陌生的东西.然而,从技术的角度来说,这对于Web系统是一个巨大的考验.当一个Web系统,在一秒钟内收到数以万计甚至更多请求时,系统的优化和稳定至关重要.这次我们 ...
- 任务调度框架-Quartz.Net
使用Quartz.Net依赖于以下3个组件:Common.Logging.dll.Common.Logging.Core.dll.Quartz.dll 简单封装 using Quartz; using ...
- android shader 用法
转自 http://blog.csdn.net/abcdef314159 http://blog.csdn.net/aigestudio/article/details/41799811 Shader ...
- 可以编辑R代码的eclipse插件
说到强大的IDE,eclipse肯定是首先会被想到的几个之一,幸运地是,R也能使用它.在http://www.walware.de/goto/statet上有个StatET的插件,专门为R而做,从此R ...
- 【Android UI】:Fragment官方文档
概述 Fragment表现Activity中UI的一个行为或者一部分.可以将多个fragment组合在一起,放在一个单独的activity中来创建一个多界面区域的UI,并可以在多个activity ...
- Global文件编译发布,代码不执行的问题与解决
问题:在Application_BeginRequest添加防止跨站点注入的过滤代码,VS2005编译成DLL发布后发现代码不会被执行: 环境:windows server 2008 r2 x64位 ...
- 基于Linux的WebSphere性能调优与故障诊断
一.关于was数据源等问题的配置 (1)关于was数据源连接池的最大.最小配置多大合适?怎样去计算? (2)关于JVM的配置,64位系统,64位WAS,最值小和最大配置多大最优?怎样去计算? (3)应 ...
- 利用反射实现类通用的DAO层
public void add(Object object) throws SQLException { ResultSet rs=null; PreparedStatement ps=null; C ...
- 【整理】--【GPIO】OK6410
S3C6410的GPIO引脚相对来说比较多,而且大部分引脚都具有多重复用功能,如何在linux上用最简单的方式来控制GPIO这需要我们好好研究一下底层的代码了,其实方法有很多种,鉴于在操作系统端控制G ...
- (原创) 巩固理解I2C协议(MCU,经验)
题外话:这几天天气突然转冷了.今天已是11月23日了,查查黄历,昨天(11月22日)刚好是小雪,一夜温度骤降,果然老祖先的经验有灵验!冬天来了,还是多加加衣服,注意保暖! 1.Abstract ...