Anroid开发艺术探索(View事件基础知识)
来源:互联网 发布:北大青鸟的网络课程 编辑:程序博客网 时间:2024/06/04 01:13
一、View基础知识
1、什么是View
View是Android中所有控件的基类,不管是Button和TextView还是复杂的RelativeLayout等,它们的共同基类都是View。所以说,View是一种界面层控件的一种抽象,它代表了一个控件。除了View还有ViewGroup,内部包含了许多个控件,即一组View。在Android的设计中,ViewGroup也是继承了View,这就意味着View本身就是可以是单个控件也可以是多个控件组成的一组控件,通过这种关系就形成了View的树结构,这和Web前端中的Dom树的概念都是相似的。根据这个概念,我们知道,Button显然是个View,而LinearLayout不但是View而且还是一个ViewGroup,而ViewGroup内部是可以有子View的,这个子View同样还可以是ViewGroup。
2、View的位置参数
View的位置主要是由它的四个顶点来决定的,分贝对应于View的四个属性:top,left,right,bottom。
从Android3.0开始,View增加了几个额外的参数:x,y,translationX,translationY。其中X和Y是View左上角的坐标,而translationX和translationY是View左上角相对于父容器的偏移量。这几个参数也是相对于父容器的坐标,并且translationX和translationY的默认值是0。View的几个参数之间的换算关系如下:
x = left + translationX
y = top + translationY
需要注意的是,View在平移过程中,top和left表示的是原始左上角的位置信息,其值并不会发生改变,此时发生的改变的是x,y,translationX和translationY这四个参数。
3、MotionEvent和TouchSlop
3.1、在手指接触屏幕后所产生的一系列事件中,典型的事件类型分为如下几种:
ACTION_DOWN ACTION_MOVE ACTION_UP
一次触摸屏幕的过程大约是这样
ACTION_DOWN -> ACTION_MOVE ... ACTION_MOVE ->ACTION_UP
上述三种情况是典型的事件序列,同时通过MotionEvent对象我们可以得到点击事件发生的
X,Y坐标。getX,getY得到的是相对于当前View的x,y坐标,getRawX,getRawY得到的是相对于手机屏幕左上角的x,y坐标
3.2、TouchSlop
TouchSlop是系统所能识别出的被认为是滑动的最小距离,当手指在屏幕上滑动时,如果两次滑动之间的距离小于这个常量,那么系统就不认为你是在进行相应的滑动操作。我们通过如下方式可以获得到这个常量:ViewConfiguration.get(getContext()).getScaledTouchSlop().
4、VelocityTracker,GestureDetector和Scroller
4.1、VelocityTracker
速度追踪,用于追踪手指在滑动的过程中的速度,包括水平和竖直方向的速度,它的使用过程很简单。首先,在View的onTouchEvent方法中追踪当前点击事件的速度:
VelocityTracker v = VelocityTracker.obtain();v.addMovement(event);
当我们知道当前的滑动速度时,这个时候就可以采用如下的方式来获取当前的速度:
v.conputeCurrentVelocity(1000);//将时间间隔设置为 1sint xVelocity = (int) v.getXVelocity();int yVelocity = (int) v.getYVelocity();
在这一步中有两个需要注意:
第一点,获取速度前必须先计算速度。第二点:速度指的是一段时间内,手指所滑动经过的像素数,而且规定,从左到右速度为正,从右到左速度为负。
4.2、GestureDetector
手势检测,用于辅助检测用户的点击,滑动,长按,双击等行为。要使用GestureDetector可参考如下过程。
首先,创建一个GestureDetector对象并实现OnGestureListener接口,根据我们的需要,我们还可以实现OnDoubleTapListener从而来监听双击行为。
GestureDetector gd = new GestureDetector(this);gd.setIsLongPressEnabled(false);//解决长按屏幕后无法拖动的现象
其次,接管目标View的onTouchEvent方法,在监听View的onTouchEvent方法中添加如下实现:
boolean consume = gd.onTouchEvent(event);return consume;//false 表示触摸事件可以继续传递,true表示传递到此终止,事件被消费
做完了上面两步,我们可以有选择的来实现OnGestureListener和OnDoubleTapListener中的方法了。
OnDoubleTapListener里面的方法有(来自Android Developer):
OnGestureListener里面的方法有(来自Android Developer):
上面表里面的方法中常用的有:onSingleTapUp(单击),onFling(快速滑动),onScroll(拖动),onLongPress(长按)和onDoubleTap(双击)。在实际的开发中,可以不使用GestureDetector,完全可以自己在onTouchEvent方法中实现自己的监听。对于GestureDetector有个比较好的练习:
在fragment里面监听触摸事件,大家如果感兴趣可以了解一下。
4.3、Scroller
弹性滑动对象,用于实现View的弹性滑动。我们知道,当使用View的scrollTo/scrollBy方法进行滑动时,其过程是瞬时间的,这个没有过程的滑动用户体验不好。这个时候我们就可以使用Scroller来实现有过度效果的滑动。Scroller本身无法让View弹性滑动,它需要和View的computeScroll方法配合使用才能共同完成这个功能。
二、View的滑动
前言:在有限的屏幕空间内为用户呈现出更多彩的内容,我们就需要通过View的滑动来实现。
掌握滑动是实现绚丽的自定义控件的基础。通过三种方式可以实现View的滑动:
1、通过View本身提供的scrollTo/scrollBy方法来实现滑动 2、通过动画给View施加平移效果来实现滑动 3、通过改变View的layoutParams使得View重新布局而实现滑动
1、使用ScrollTo/ScrollBy
为了使用View的滑动,View提供了专门的方法来实现这个功能,那就是scrollTo和scrollBy。下面是两者的实现。
scrollBy实际上也是调用了scrollTo方法,它实现了当前位置的相对滑动,scrollTo它实现了基于当前位置的绝对滑动。利用scrollTo和scrollBy来实现View的滑动不是一件困难的事,但是我们要明白滑动过程中View内部的两个属性mScrollX和mScrollY的改变规则。
在滑动过程中,mScrollX的值总是等于View左边缘和View中的内容左边缘在水平方向上的距离,而mScrollY的值总是等于View上边缘和View内容上边缘在竖直方向上的距离,scrollTo和scrollBy只能改变View内容的位置而不能该百年View在布局中的位置。mScrollX,和mScrollY的单位为像素,并且当View左边缘在View内容左边缘右边时,mScrollX为正值,反之为负。当View上边缘在View内容上边缘的下边时,mScrollY为正值,反之为负。换句话说,如果从左向右滑动。那么mScrollX为负值,反之为正。如果从上往下滑动,mScrollY为负值,反之为正。
不管怎么样滑动,View本身的位置是不变的,改变的是VIew里面的内容
2、使用动画
通过动画我们能够让一个View进行平移,而平移就是一种滑动。使用动画来移动View主要是操作View的translationX和translationY属性,既可以采用传统的View动画,也可以采用属性动画。
采用如下代码在100ms内,将一个View从原始位置移动向右下角移动100像素
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true" android:zAdjustment="normal"> <translate android:duration="100" android:fromXDelta="0" android:fromYDelta="0" android:interpolator="@android:anim/linear_interpolator" android:toYDelta="100" android:toXDelta="100" /></set>
如果是采用属性动画的话,则会更简单,下面的代码是将一个View从原始位置向右平移100像素
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();
上面提到View动画并不能真正的改变View的位置,这回带来一个很严重的问题。试想一下,比如我们通过VIew动画将一个Button向右移动100px,并且这个View设置有单击事件,然后你会很惊奇的发现,单击新位置无法触发onClick事件,而单击原始位置仍然可以触发onClick事件,尽管button已经不在原始位置了。从Android3.0开始,使用属性动画可以解决上面的问题,但是由于要兼容Android2.2,Android2.2上无法使用属性动画,因此这里还是有问题。但是这个问题可以被间接解决,针对上面的动画问题,我们可以在新位置上预先创建一个和目标Button相同的Button,动画开始前它是隐藏的,动画开始后,隐藏原始Button,显示预留Button.
3、改变布局参数
第三种实现View滑动的方法就是改变布局参数,即改变LayoutParams。如果我们想把一个Button向右平移100px,我们只需要将这个Button的LayoutParams里的marginLeft参数增加100px即可。除此之外,为了达到移动Button的目的,我们可以在Button的左边放一个空的View,这个空的View的默认宽度为0,当我们需要向右移动Button时,我们只需要重新设置空View的宽度即可(假设Button的父容器是水平方向的LinearLayout)。下面是重新设置一个View的LayoutParams方法:
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)mButton1.getLayoutParams();layoutParams.width += 100;layoutParams.leftMargin += 100;mButton1.requestLayout();//或者mButton1.setLayoutParams(layoutParams)
通过LayoutParams的方式去实现View的滑动同样是一种很灵活的方法。
4、各种滑动方式的对比
上面分别介绍了三种不同的滑动方式,它们都能实现View的滑动,那么它们之间的区别是什么呢?
先看scrollTo/scrollBy这种方式,它是View提供的原生方法,起作用是专门用于View的滑动,它可以比较方便的实现滑动效果,并且不影响内部元素的单击事件..但是它的缺点也是明显的:它只可以滑动View的内容,不可以滑动View的本身。
通过动画实现View的滑动,如果是3.0以上系统,采用属性动画来做滑动这种方式没有明显的缺点。而且一些复杂的动画效果,必须要通过动画才能实现。
通过改变布局这种方式,它处理使用起来麻烦一些外也没有明显的缺点。主要的运用对象是一些具有交互性的View。因为这些View需要和用户交互,直接通过动画去实现会有问题,所以这个时候我们可以使用直接改变布局参数的方式去实现。
备注:节选自Android开发艺术探索–任玉刚
- Anroid开发艺术探索(View事件基础知识)
- Anroid开发艺术探索(View事件分发)
- Android 艺术开发探索读后感-view基础知识
- View事件体系(Android开发艺术探索读书笔记)
- 《Android开发艺术探索》--View事件分发
- Android开发艺术探索(连载)之View的事件体系(二)View的滑动
- 《Android开发艺术探索》之学习笔记(三)View的基础知识
- 《Android开发艺术探索》读书笔记--part3 View的事件体系
- 《Android开发艺术探索》——View的事件体系
- Android开发艺术探索 读书笔记 第三章 View事件体系
- 《Android开发艺术探索》之View事件分发机制
- View的事件分发机制《android开发艺术与探索》
- 开发艺术探索--Android的View事件体系
- Android开发艺术探索<View的点击事件触发过程>
- 《Android开发艺术探索》第三章View事件体系小结
- Android 开发艺术探索笔记-View的事件分发
- 《Android开发艺术探索》——View事件分发机制
- Android开发艺术探索读书笔记-View的事件体系(一)
- Java多线程基础--05之 线程等待与唤醒
- 如何动态的制作级联菜单(上)
- Jquery获取元素距离文档顶部的距离
- 微擎架构
- 天赋!被我们忽略的财富!
- Anroid开发艺术探索(View事件基础知识)
- Redis的特点及与Memcache的特点的区别
- 搜索例题
- jdk1.8 J.U.C并发源码阅读------ReentrantReadWriteLock源码解析
- 阿里热修复框架Sophix
- java 面向对象基础编程
- php代码不支持<? ?>
- [SMOJ2074]RP路
- 泛型的有关知识