阅读本章你将了解:
1.MotionEvent(运动事件)
2.TouchSlop(触摸坡;最小滑动距离,每个手机大小不一)
3.VelocityTracker (速度追踪)
4.GestureDetector(手势检测器)
5.Scroller(弹性滑动)
3.1 view的基础知识
什么是view
view extends View
ViewGroup extends View
3.1.2
View的4个属性:
top 左上角纵坐标
left 左上角横坐标
bottom 右下角纵坐标
right 右下角横坐标
View的宽高和坐标关系:
left = getLeft();
right= getRight();
top= getTop()
bottom = getBottom();
width = right -left;
height = bottom - top;
3.0新增参数:View平移的时候只有x,y,translationX,translationY改变
x = left + translationX;
y = top + tanslationY;
3.1.3
MotionEvent(运动事件)和TouchSlop (最小滑动距离)
MotionEvent:
MotionEvent.ACTION_DOWN 接触
MotionEvent.ACTION_MOVE 移动
MotionEvent.ACTION_UP 松开
getX/getY 当前view左上角x,y坐标
getRawX/getRawY 手机屏幕左上角x,y坐标
TouchSlop:
ViewConfiguration.get(this).getScaledTouchSlop();常量
3.1.4
VelocityTracker (速度追踪)丶GestureDetector(手势检测器)
1.VelocityTracker (速度追踪):
速度 = (终点位置 - 起点位置)/时间段
手指逆着坐标系的正反向滑动,速度是负值
@Override
public boolean onTouchEvent(MotionEvent event) {
//在view的onTouchEvent追踪点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
//1s内划过的像素
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
//用完了重置回收
velocityTracker.clear();
velocityTracker.recycle();
return super.onTouchEvent(event);
}
2.GestureDetector(手势检测器):
常用的方法:
onSingleTapUp(单击)onFling(快速滑动)onScroll(拖动)onLongPress(长按)onDoubleTap(双击)
建议:滑动相关,直接在onTouchEvent实现;双击使用GestureDetector
3.2
View的滑动
三种方式:
1.使用scrollTo/scrollBy 2.动画平移 3.改变view的LayoutParams
1.使用scrollTo/scrollBy
scrollTo/scrollBy方法只能改变view内容的位置,不能改变view位置
从上往下滑动:getScrollY < 0 反之:getScrollY > 0
从左往右滑动:getScrollX < 0 反之:getScrollX > 0
2.动画平移
使用属性动画(>3.0)
View v = null ;
ObjectAnimator.ofFloat(v,”translationX”,0,100).setDuration(1000).start();
3.0以前上述代码会出现:view移动了,”真身”还在原地,点击原地触发onClick
3.0以后没有问题了
3.改变view的LayoutParams
View v = null;
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
layoutParams.width += 100;
layoutParams.leftMargin += 100;
v.requestLayout();
//或者 v.setLayoutParams(layoutParams);
几种方式的比较:
scrollTo/scrollBy:操作简单,适合view内容滑动
动画:不交互的view(点击事件故障)
改变view的layoutParams:操作复杂,适用于有交互的view
3.3 Scroller(弹性滑动)
1.使用Scroller实现弹性滑动
Scroller本身无法让View弹性滑动,它需要和View的computeScroll方法配合
package com.weiwei.zx.wp;
import android.content.Context;
import android.view.View;
import android.widget.Scroller;
/**
* Created by zx on 2016/1/7.
*/
public class MyView extends View {
private Scroller mScroller;
public MyView(Context context) {
super(context);
mScroller = new Scroller(context);
//缓慢滚动到指定位置
smoothScrollTo(2,2);
}
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
//1s内滑向destX,效果就是慢慢滑动
//startScroll(滑动的起点)
mScroller.startScroll(scrollX,0,delta,0,1000);
invalidate();//view重绘
}
@Override
public void computeScroll() {
if(mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
}
原理:多次view重绘导致view多次小幅度滑动(弹性滑动)
1.调用invalidate()不断让view重绘
2.通过重绘距滑动起始时间间隔,得到view当前滑动位置
3.通过scrollTo滑动
2.使用动画实现弹性滑动(view的内容滑动)
动画天然就具有弹性效果,思想和scroller类似
3.使用延时策略
思想:不断的发送延时消息,实现弹性效果(handle.postDelayed)
3.4 View的事件分发机制
1.touchEvent传递到顶层view的dipatchTouchEvent
2.由dipatchTouchEvent分发;返回true,交给touchEvent处理;false交给onIntercepterTouchEvent处理
3、onIntercepterTouchEvent返回true交给它的touchEvent处理,返回false传递给子view
总结:onInterceptTouchEvent是自rootiew向下传递, onTouchEvent正好相反。
3.5 View的滑动冲突
场景:
1.外部滑动方向和内部滑动方向不一致(viewpager+fragment)
2.外部滑动方向和内部滑动方向一致(listview+listview)
3.上面2中情况的嵌套
解决方法:
1.外部拦截法(通过滑动距离差,符合view的事件分发机制)
重写onInterceptTouchEvent方法,在方法中做相应拦截
2.内部拦截法(配合requestDisallowInterceptTouchEvent,和事件分发机制不一致)
推荐使用:
外部拦截法(简单易用)