Android系统知识全览---View知识体系(2)---Vi
View的事件体系
- View的概念
- View的事件
- View的滑动事件
- View事件分发机制
- View的滑动冲突解决
View的概念
View是界面上控件的在代码层的抽象体现。所有控件继承于View基类,根据功能可以分为View和ViewGroup。其中ViewGroup表示控件组,可以放置控件View。
View的属性参数
View的位置属性:
left、right、top、bottom、elevation
image如图所示:
- left:目标View的最左边和这个View所在父控件的最左边的距离,通过view.getLeft()方法获取;
- right:目标View的最右边和这个View所在父控件的最左边的距离,通过view.getRight()方法获取;
- top:目标View的最上边和这个View所在父控件的最上边的距离,通过view.getTop()方法获取;
- bottom:目标View的最下边和这个View所在父控件的最上边的距离,通过view.getBottom()方法获取;
- elevation:目标View的Z轴高度和这个View所在的父控件所在的Z轴高度的距离,通过view.getElevation()方法获取(这个属性是Android 5.0之后添加的新属性)。
同理可以得出View.width=right-left,View.height=bottom-top
translationX、translationY、translationZ
这三个参数代表的是在动画或者滑动View的时候,View的当前位置相对于其原始位置平移的距离:
translation 翻译; 译本; 转化; 转变;
- translationX:在滑动过程中,View当前位置的最左边和这个View原始位置的最左边的距离,通过view.getTranslationX()方法获取;
- translationY:在滑动过程中,View当前位置的最上边和这个View原始位置的最上边的距离,通过view.getTranslationY()方法获取;
- translationZ:在动画过程中,View当前位置的Z轴高度和这个View原始Z轴高度的距离,通过view.getTranslationZ()方法获取(这个方法是Android 5.0之后添加的新方法)。
x、y、z
这三个参数代表的是View的当前位置相对于其父控件的距离:
- x:目标View的当前位置的最左边和这个View所在父布局的最左边的距离,通过view.getX()方法获取;
- y:目标View的当前位置的最上边和这个View所在父布局的最上边的距离,通过view.getY()方法获取;
-
z:目标View的当前位置的Z轴位置和这个View所在父布局的Z轴位置的距离,通过view.getZ()方法获取(这个方法是Android 5.0之后添加的新方法)。
这三个参数和前面的几个参数的关系公式如下:
x = left + translationX;
y = top + translationY;
z = elevation + translationZ;
值得注意的是 View在平移动作,参考点是左上角 所以 所谓的移动距离也只能是相对于左上角坐标的变化。
View的事件
MotionEvent和TouchSlop
View可以接受和处理类似点击 长按 双击等动作。这里有个MotionEvent可以接受处理。
- ACTION_DOWN:手指刚刚触摸到屏幕时触发的事件;
- ACTION_MOVE:手指在屏幕上移动的时候触发的事件;
- ACTION_UP:手指从屏幕上抬起的一瞬间触发的事件。
因此,对于我们常常做的一些操作,相应的事件触发顺序如下:
- 点击屏幕后立刻抬起手指:DOWN -> UP
- 滑动屏幕:DOWN -> MOVE -> ... -> MOVE -> UP
使用MotionEvent类,我们还可以获取到触摸屏幕时View的一些位置参数:
- x:当前触摸的位置相对于目标View的X轴坐标,通过getX()方法获取;
- y:当前触摸的位置相对于目标View的Y轴坐标,通过getY()方法获取;
- rawX:当前触摸的位置相对于屏幕最左边的X轴坐标,通过getRawX()方法获取;
- rawY:当前触摸的位置相对于屏幕最上边的Y轴坐标,通过getRawY()方法获取
TouchSlop指的是 认为是滑动的最小距离。也就是在屏幕上滑动距离大于等于这个数才能算是滑动。
通过如下方式即可获取这个常量
ViewConfiguration.get(getContext()).getScaledTouchSlop();
View事件的工具类VelocityTracker/GestureDetector/Scroller
VelocityTracker
VelocityTracker用于追踪手指滑动的速度。具体使用过程如下:
public class TestVelocityView extends View {
//用于回调的接口
GetVelocityListener listener;
//追踪速度关键的类。没有这个这篇文章将毫无意义
VelocityTracker velocityTracker;
//要画文字或者任何东西都需要的paint
Paint paint = new Paint();
public GetVelocityListener getListener() {
return listener;
}
public void setListener(GetVelocityListener listener) {
this.listener = listener;
}
public TestVelocityView(Context context) {
this(context,null);
}
public TestVelocityView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public TestVelocityView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint.setTextSize(50);
}
@Override
protected void onDraw(Canvas canvas) {
//画文字的代码。
canvas.save();
paint.setColor(Color.BLACK);
canvas.drawText("x = "+xVelocity+"y ="+yVelocity,getLeft(),getTop(),paint);
//画完之后回收一下
canvas.restore();
}
int xVelocity = 0;
int yVelocity = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//初始化
velocityTracker = VelocityTracker.obtain();
break;
case MotionEvent.ACTION_MOVE:
//追踪
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
xVelocity = (int) velocityTracker.getXVelocity();
yVelocity = (int) velocityTracker.getYVelocity();
if (listener != null) {
listener.get(xVelocity, yVelocity);
//强制刷新一下view,否则不会一直掉onDraw。
invalidate();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//回收
velocityTracker.clear();
velocityTracker.recycle();
break;
}
return true;
}
public interface GetVelocityListener {
public void get(int x, int y);
}
}
- 实例化VelocityTracker对象
velocityTracker = VelocityTracker.obtain();
- TouchEvent方法中给VelocityTracker对象绑定MotionEvent对象
- 使用computeCurrentVelocity设置速度的时间单位(会影响到后面获取的结果)比如设置为100ms v=100/100ms,如果设置为1000ms,得出的结果为v=1000/1000ms。
- 获取 横向 纵向 速度
xVelocity = (int) velocityTracker.getXVelocity();
yVelocity = (int) velocityTracker.getYVelocity();
最后记得回收:
velocityTracker.clear();
velocityTracker.recycle();
GestureDetector
手势检测的工具类,用于检测用户的单击 双击 滑动 长按等事件。
具体使用如下:
0.继承GestureDetector.OnGestureListener
接口
于此同时还有6个方法:
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
return false;
}
1.定义手势检测器实例,使用``GestureDetector.OnGestureListener`实例化对象。
GestureDetector detector=new GestureDetector(this);
//解决长按无法移动屏幕问题
detector.setIsLongpressEnabled(false);
2.View的onTouchEvent中 直接交给
@Override
public boolean onTouchEvent(MotionEvent me) {
//将该Activity上的触碰事件交给GesturDetector处理
return detector.onTouchEvent(me);
}
3.除了以上的6个事件,还有一些而外的事件需要单独添加接口OnDoubleTapListener
。
detector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
});
1.onSingleTapConfirmed 严格的单击事件
2.onDoubleTap 双击事件 不和 onSingleTapConfirmed 一起
3.onDoubleTapEvent 发生了双击事件
Scroller
弹性滑动辅助类,能帮助View实现一个带过度的滑动。
使用如下:
View的滑动
使用上节介绍的Scroller即可,当然也可以用其他方式
普通的滑动()
1.scrollTo、scrollBy 只能滑动View的内容 生硬
- 使用动画位移 但是View动画只能滑动UI,不能真正滑动View。使用属性动画可以,通过动画改变translationX 和translationY
3.改变View的布局参数 设置LayoutParams的Margin参数即可
使用Scroller能弹性的滑动过去。