View的事件体系
View基本知识
1.View的位置由四个定点决定,分别是top/right/bottom/left,且这些坐标的位置都是相对于View的父容器来说的(相对坐标)。
2.View的宽高
width=right-left;
height=bottom-top;
3.MotionEvent
- 常用点击事件类型
1.ACTION_DOWN
2.ACTION_MOVE
3.ACTION_UP
4.ACTION_CANCEL
- getX()/getY()/getRawX()/getRawY()
1.getX()/getY()是相对于当前View的左上角的x和y坐标
2.getRawX()/getRawY()是相对于屏幕左上角的x和y坐标
4.TouchSlop
- TouchSlop是系统所能识别出的被认为是滑动的最小距离,也就是,手指在屏幕上滑动时,如果两次滑动之间的距离小于这个常量,那么系统就不会认为你是在进行滑动操作。这是一个常量,跟设备有关。
- 2.可通过ViewConfiguration.get(context).getScaledTouchSlop()获取TouchSlop常量
- 这个常量的数值可从frameworks/base/core/res/res/values/config.xml查看
5.VelocityTracker
- 速度追踪,用于追踪手指在滑动过程中的速度,包括水平和垂直方向的速度。
- 使用方法
1.在View的onTouchEvent方法中追踪当前点击事件的速度。
VelocityTracker tracker=VelocityTracker.obtain();
tracker.addMovement(event);
2.获取当前的滑动速度
//获取在1000ms内移动的像素数
tracker.computeCurrentVelocity(1000);
int xVelocity=(int)tracker.getXVelocity();
int yVelocity=(int)tracker.getYVelocity();
3.在不需要的时候需要进行资源回收
tracker.clear();
tracker.recycle();
- 在getXVelocity()/getYVelocity()之前必须要调用computeCurrentVelocity()
- computeCurrentVelocity的参数表示的是一个时间间隔,以毫秒为单位,计算速度时得到的速度就是在这个时间间隔内手指在水平或垂直方向上所滑动的像素数。
6.GestureDetector
- 手势监测,用于辅助监测用户的单击、滑动、长按、双击等行为。
- 使用方法
1.创建一个GestureDetector对象并实现OnGestureListener接口。
GestureDetector gestureDetector=new GestureDetector(this);
//解决长按屏幕后无法拖动的现象
gestureDetector.setIsLongpressEnabled(false);
2.接管目标View的onTouchEvent方法
boolean consume=gestureDetector.onTouchEvent(event);
return resume;
3.有选择的实现OnGestureListener和onDoubleTapListener回调中的方法。
- OnGestureListener和onDoubleTapListener中的回调方法
方法名 | 描述 | 所属接口 |
---|---|---|
onDown | 手指轻触屏幕一瞬间,由一个ACTION_DOWN事件触发 | OnGestureListener |
onShowPress | 手指轻触屏幕,尚未松开或拖动,由一个ACTION_DOWN事件触发 | OnGestureListener |
onSingleTapUp | 手指松开,触发ACTION_UP,点击行为 | OnGestureListener |
onScroll | 手指按下屏幕并拖动 ACTION_DOWN + ACTION_MOVE | OnGestureListener |
onLongPress | 长按屏幕不放 | OnGestureListener |
onFling | 快速滑动,ACTION_DOWN + ACTION_MOVE + ACTION_UP | OnGestureListener |
onDoubleTap | 双击,不与onSingleTapConfirmed并存 | OnDoubleTapListener |
onSingleTapConfirmed | 严格的单击行为 | OnDoubleTapListener |
onDoubleTapEvent | 表示发生了双击行为 | OnDoubleTapListener |
7.Scroller
- 弹性滑动对象,用于实现View的弹性滑动。
- Scroller本身无法让View弹性滑动,它需要和View的computeScroll方法配合使用才能共同完成这个功能。
- Scroller工作机制简介
Scroller本身并不能实现View的滑动,它需要配合View的computeScroll方法才能实现弹性滑动的效,它不断让View重绘,而每一次重绘距滑动起始时间会有一个时间间隔,通过这个时间间隔Scroller就可以得出View当前的滑动位置,知道了滑动位置就可以通过scrollTo方法来完成View的滑动。就这样,View的每一次重绘都会导致View进行小幅度的滑动,而多次的小幅度滑动就组成了弹性滑动。
- 使用方法
Scroller scroller=new Scroller(context);
private void smoothScrollTo(int destX,int destY){
int scrollX=getScrollX();
int delta=destX-scrollX;
//1000ms内滑动到destX
scoller.startScroll(scrollX,0,delta,0,1000);
invalidate();
}
@Override
public void computeScroll(){//该方法在父类中是空实现
if(scroller.computeScrollOffset()){//滑动是否结束
scrollTo(scroller.getCurrX(),
scroller.getCurrY());
postInvalidate();
}
}
View的滑动
1.实现View滑动的三种方式
1.通过View本身提供的scrollTo/scrollBy方法来实现滑动
2.通过动画给View施加平移效果实现滑动
3.通过改变View的LayoutParams使得View重新布局来实现滑动
2.使用scrollTo/scrollBy实现滑动
- 只能讲View的内容进行平移,并不能将View本身的位置进行移动
- scrollBy实际上调用了scrollTo方法,它实现了基于当前位置的相对滑动。
- scrollTo实现了基于所传递参数的绝对滑动。
- mScrollX等于View左边缘和View内容左边缘在水平方向的距离
- mScrollY等于View的上边缘和View内容上边缘在垂直方向的距离
3.使用动画实现滑动
- 使用动画来移动View,主要是操作translationX和translationY属性
- View动画是对View的影像进行操作,并不能真正改变View的位置参数,包括宽高
- 如果希望动画后的状态得以保留还必须将fillAfter设置为true
示例代码
- 1.使用ObjectAnimator
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(1000).start;
- 2.使用ValueAnimator
final int startX=0; final int deltaX=100; ValueAnimator animator=ValueAnimator.ofInt(0,1).setDuration(1000); animator.addUpdateListener(new AnimatorUpdateListener(){ @Override public void onAnimationUpdate(ValueAnimator animator){ float fraction=animator.getAnimatedFraction(); targetView.scrollTo(startX+(int)(deltaX*fraction),0); } }; animator.start();
4.改变布局参数实现滑动
示例代码:
MarginLayoutParams params=(MarginLayoutParams)button.getLayoutParams();
params.width+=100;
params.leftMargin+=100;
button.requestLayout();
//或者button.setLayoutParams(params);
5.各种实现滑动的方式比较
方式 | 特点 |
---|---|
scrollTo/scrollBy | 操作简单,适合对View内容的滑动 |
动画 | 操作简单,主要使用于没有交互的View和实现复杂的动画效果 |
改变布局参数 | 操作稍微复杂,适用于有交互的View |
6.使用延时策略
- 通过发送一系列延时消息从而达到一种渐进式的效果
- 可以使用Handler或者View的postDelayed方法,也可以使用线程的sleep方法
- 使用Handler方式实现1000ms内将View的内容向左移动100像素的效果
private static final int MESSAGE_SCROLL_TO=1;
private static final int FRAME_COUNT=30;
private static final int DELAYED_TIME=30;
private int mCount=0;
@SuppressLint("HandlerLeak")
private Handler mHandler=new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case MESSAGE_SCROLL_TO:
mCount++;
if(mCount<=FRAME_COUNT){
float fraction=mCount/(float)FRAME_COUNT;
int scrollX=(int)(fraction * 1000);
targetView.scrollTo(scrollX,0);
targetView.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);
}
break;
default:
break;
}
}
};