View
什么是View
View是Android中所有控件的基类,view本身可以是单控件也可以是由多控件组成的控件
View的位置参数:
‘
View自身提供的获取坐标的方法:
getTop():获取view自身的顶边到其父布局顶边的距离。
getLeft():获取view自身的左边到其父布局左边的距离。
getRight():获取view自身的右边到其父布局左边的距离。
getBottom():获取view自身的底边到其父布局顶边的距离。
MotionEvent
手指接触屏幕锁产生的事件,常用的如下:
ACTION_DOWN——手指刚接触屏幕
ACTION_MOVE——手指在屏幕上移动
ACTION_UP——手指从屏幕上松开的一瞬间
MotionEvent提供的方法:
getX() :获取点击事件距离控件左边的距离,即视图坐标。
getY() :获取点击事件距离控件顶边的距离,即视图坐标。
getRawX():获取点击事件距离整个屏幕左边的距离,即绝对坐标。
getRawY():获取点击事件距离整个屏幕顶边的距离,即绝对坐标。
TouchSlop
根据方法注释理解这个touchSlop是一个滑动距离值的常量,也就是说当我们手触摸在屏幕上滑动时,如果滑动距离没有超过touchSlop值的话 ,android系统本身是不会认为我们在屏幕上做了手势滑动,因此只有当我们在屏幕上的滑动距离超过touchSlop值时,android系统本身才会认为我们做了滑动操作并去响应触摸事件,不过要注意的是不同的设备,touchSlop的值可能是不同的,一切以上述的函数获取为准
VelocityTracker
VelocityTracker是个速度跟踪类,用于跟踪手指滑动的速度,包括x轴方向和y轴方向的速度。
使用过程:在view的onTouchEvent方法中追踪当前单击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain(); velocityTracker.addMovement(event);
当我们想知道当前的滑动速度时,可以采用如下方式来获取当前的速度:
velocityTracker.computeCurrentVelocity(1000); int xVelocity = (int) velocityTracker.getXVelocity(); int yVelocity = (int) velocityTracker.getYVelocity();
如果不需要使用它时,需要调用clear方法来重置并回收内存:
velocityTracker.clear(); velocityTracker.recycle();
computeCurrentVelocity (int units),基于当前我们所收集到的点计算当前的速率,当我们确定要获得速率信息的时候,在调用该方法,因为使用它需要消耗很大的性能。
参数:units 我们想要指定的得到的速度单位,如果值为1,代表1毫秒运动了多少像素。如果值为1000,代表1秒内运动了多少像素。这个方法还有一个重载函数 computeCurrentVelocity (int units, float maxVelocity), 跟上面一样也就是多了一个参数。
参数:maxVelocity 该方法所能得到的最大速度,这个速度必须和你指定的units使用同样的单位,而且必须是整数.也就是,你指定一个速度的最大值,如果计算超过这个最大值,就使用这个最大值,否则,使用计算的的结果,
这个最大速度可以通过ViewConfiguration.get(context).getScaledMaximumFlingVelocity()方式获取。
getXVelocity()和getYVelocity() ,这两个很简单,获得横向和竖向的速率。前提是一定要先调用computeCurrentVelocity (int units)函数计算当前速度!
速度的计算公式,可以用下列公式来表示,所以说速度可以时负数:
速度 = (终点位置 - 起点位置) / 时间段
GestureDetector
手势监听类,用于辅助检测用户的单击、滑动、长按、双击等行为
使用:先创建一个GestureDetector对象并实现OnGestureListener接口,根据需要还可以实现OnDoubleTapListener从而能够监听双击行为:
GestureDetector gestureDetector = new GestureDetector(this); //解决长按屏幕后无法拖动的现象 gestureDetector.setIsLongpressEnabled(false);
接着,接管目标View的onTouchEvent方法,在需要等待监听的View中的onTouchEvent方法中添加如下实现:
boolean consume = gestureDetector.onTouchEvent(event); return consume;
OnGestureListener中的接口:
// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发 public boolean onDown(MotionEvent arg0) { Log.i("MyGesture", "onDown"); Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show(); return true; } /* * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发 * 注意和onDown()的区别,强调的是没有松开或者拖动的状态 */ public void onShowPress(MotionEvent e) { Log.i("MyGesture", "onShowPress"); Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show(); } // 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发 // 非常快的点击Touchup:onDown>onSingleTapUp>onSingleTapConfirmed // 稍微慢点的点击Touchup:onDown>onShowPress>onSingleTapUp>onSingleTapConfirmed public boolean onSingleTapUp(MotionEvent e) { Log.i("MyGesture", "onSingleTapUp"); Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show(); return true; } // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 // 参数一:第一个MotionEvent // 参数二:最后一个MotionEvent // 参数三:velocityX X轴上的移动速度,像素/秒 // 参数四:velocityY Y轴上的移动速度,像素/秒 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.i("MyGesture", "onFling"); Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show(); return true; } // 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发 // 滑屏:手指触动屏幕后,稍微滑动后立即松开onDown-->onScroll-->onScroll-->onScroll-->onFling // 拖动: onDown-->onScroll-->onScroll-->onFiling public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.i("MyGesture", "onScroll"); Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show(); return true; } // 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发 //触发顺序:onDown->onShowPress->onLongPress public void onLongPress(MotionEvent e) { Log.i("MyGesture", "onLongPress"); Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show(); }
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; }
google官方api:
https://developer.android.com/reference/android/view/GestureDetector.OnDoubleTapListener
Scroller
弹性滑动对象,用来实现View的弹性滑动,Scroller本身无法让view弹性滑动,它需要和view的computeScroll方法配合使用才能共同完成这个功能。
View的滑动
实现view滑动的三种方式:
- 通过view本身提供的scrollTo/scrollBy方式来实现
- 通过动画给view施加平移效果来实现
- 通过改变view的LayoutParams使用view重新布局从而实现滑动
使用ScrollTo/ScrollBy
scrollTo跟scrollBy其移动的本质都是View/ViewGroup中的内容,并且移动的过程都是瞬间完成的
scrollTo喝scrollBy都是View中的方法,不是Scroller中的方法,但是控制View的平滑移动与Scroller类密不可分。
scrollTo() : **指是的移动的绝对位置,如果位置没有变化,多次调用则不会起作用。
scrollBy() : **其本质依然是调用的scrollTo(),指的的移动当前位置的相对距离(每次都是先将当前的位置和设置的距离相加之和调用scrollTo(),这样如果你多次调用,你就会发现其每次都会移动一段距离,这是和scrollTo()的本质区别)
/** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the x position to scroll to * @param y the y position to scroll to */ public void scrollTo(int x, int y) { if (mScrollX != x || mScrollY != y) { int oldX = mScrollX; int oldY = mScrollY; mScrollX = x; mScrollY = y; invalidateParentCaches(); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (!awakenScrollBars()) { postInvalidateOnAnimation(); } } } /** * Move the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the amount of pixels to scroll by horizontally * @param y the amount of pixels to scroll by vertically */ public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
scrollBy实际上也是调用了scrollTo方法,它实现了基于当前位置的相对滑动,而scrollTo则实现了基于所传递参数的绝对滑动
view如果从左向右滑动,那么mScrollX为负值,否则为正值;如果从上往下滑动,那么mScrollY为负值,否则为正值
使用动画
通过动画可以让一个view进行平移,平移也可以说是一种滑动,使用动画来移动view,主要是操作view的translationX和translationY属性,既可以采用传统的view动画,也可以使用属性动画
改变布局参数
如果想给button向右移动,只需要将这个button的LayoutParams里的marginLeft参数的值增加100px即可
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams(); params.width += 100; params.leftMargin += 100; button.setLayoutParams(params);
三种滑动方式的对比:
- scrollTo/scrollBy:操作简单,适合对View内容的滑动;
- 动画:错做简单,主要适用于没有交互的View和实现复杂的动画效果;
- 改变布局参数:操作稍微复杂,适用于有交互的View
转载于:https://my.oschina.net/u/3705875/blog/1788946