Android View滑动相关的基础知识点
来源:互联网 发布:java教程免费下载 编辑:程序博客网 时间:2024/05/21 19:21
本文涉及到的知识点:MotionEvent、ViewConfiguration、VelocityTracker 、GestureDetector、scrollTo、scrollBy、Scroller、OverScroller
MotionEvent
ACTION_DOWN :手指刚接触到屏幕
ACTION_MOVE :手指在屏幕上移动
ACTION_UP :手指在屏幕上松开的一刹那
ACTION_CANCEL:当前滑动手势被打断
1、如果点击屏幕立即松开,事件顺序 ACTION_DOWN->ACTION_UP
2、如果点击屏幕滑动然后松开,事件顺序 ACTION_DOWN->ACTION_MOVE->ACTION_UP
3、ACTION_CANCEL是当前滑动手势被打断时调用,比如在某个控件保持按下操作,然后手势从控件内部转移到外部,此时控件手势事件被打断,会触发ACTION_CANCEL
MotionEvent类中有两组方法 getX()/getY() 以及getRawX()/getRawY(),由此我们可以得到点击事件的x坐标和y坐标,他们之间不同的是getX()/getY() 返回的是相当于当前View左上角的x和y坐标,getRawX()/getRawY()返回的是相当于手机屏幕左上角的x和y坐标。
ViewConfiguration
主要用到下面三个:
1、getScaledTouchSlop():
ViewConfiguration.get(getContext()).getScaledTouchSlop()返回一个int类型的值,表示被系统认为的滑动的最小距离,小于这个值系统不认为是一次滑动 。
2、getScaledMaximumFlingVelocity()
ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity()获得一个fling手势动作的最小速度值。
3、getScaledMinimumFlingVelocity()
ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity()获得一个fling手势动作的最大速度值。
VelocityTracker
VelocityTracker 是一个跟踪触摸事件滑动速度的帮助类,用于实现flinging 及其他类似的手势,它的使用流程:
*1、通过VelocityTracker.obtain()来获得VelocityTracker 实例,
2、通过velocityTracker.addMovement(event)将用户的滑动事件传给velocityTracker
3、通过velocityTracker.computeCurrentVelocity(int units, float maxVelocity)来开始计算速度,然后调用getXVelocity(int)和getYVelocity(int)得到每个指针id检索速度。*
官网给的一个例子 Tracking Movement:
public class MainActivity extends Activity { private static final String DEBUG_TAG = "Velocity"; ... private VelocityTracker mVelocityTracker = null; @Override public boolean onTouchEvent(MotionEvent event) { int index = event.getActionIndex(); int action = event.getActionMasked(); int pointerId = event.getPointerId(index); switch(action) { case MotionEvent.ACTION_DOWN: if(mVelocityTracker == null) { // Retrieve a new VelocityTracker object to watch the velocity of a motion. mVelocityTracker = VelocityTracker.obtain(); } else { // Reset the velocity tracker back to its initial state. mVelocityTracker.clear(); } // Add a user's movement to the tracker. mVelocityTracker.addMovement(event); break; case MotionEvent.ACTION_MOVE: mVelocityTracker.addMovement(event); // When you want to determine the velocity, call // computeCurrentVelocity(). Then call getXVelocity() // and getYVelocity() to retrieve the velocity for each pointer ID. mVelocityTracker.computeCurrentVelocity(1000); // Log velocity of pixels per second // Best practice to use VelocityTrackerCompat where possible. Log.d("", "X velocity: " + VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId)); Log.d("", "Y velocity: " + VelocityTrackerCompat.getYVelocity(mVelocityTracker, pointerId)); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // Return a VelocityTracker object back to be re-used by others. mVelocityTracker.recycle(); break; } return true; }}
GestureDetector
GestureDetector相比于OnTouchListener提供了更多的手势操作,GestureDetector类对外提供了两个接口:OnGestureListener,OnDoubleTapListener,还有一个内部类SimpleOnGestureListener
OnGestureListener有下面的几个动作:
按下(onDown): 刚刚手指接触到触摸屏的那一刹那,就是触的那一下。
抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作。
长按(onLongPress): 手指按在持续一段时间,并且没有松开。
滚动(onScroll): 手指在触摸屏上滑动。
按住(onShowPress): 手指按在触摸屏上,它的时间范围在按下起效,在长按之前。
抬起(onSingleTapUp):手指离开触摸屏的那一刹那。
官网给的例子:Detecting Common Gestures :
public class MainActivity extends Activity implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener{ private static final String DEBUG_TAG = "Gestures"; private GestureDetectorCompat mDetector; // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Instantiate the gesture detector with the // application context and an implementation of // GestureDetector.OnGestureListener mDetector = new GestureDetectorCompat(this,this); // Set the gesture detector as the double tap // listener. mDetector.setOnDoubleTapListener(this); } @Override public boolean onTouchEvent(MotionEvent event){ this.mDetector.onTouchEvent(event); // Be sure to call the superclass implementation return super.onTouchEvent(event); } @Override public boolean onDown(MotionEvent event) { Log.d(DEBUG_TAG,"onDown: " + event.toString()); return true; } @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { Log.d(DEBUG_TAG, "onFling: " + event1.toString()+event2.toString()); return true; } @Override public void onLongPress(MotionEvent event) { Log.d(DEBUG_TAG, "onLongPress: " + event.toString()); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d(DEBUG_TAG, "onScroll: " + e1.toString()+e2.toString()); return true; } @Override public void onShowPress(MotionEvent event) { Log.d(DEBUG_TAG, "onShowPress: " + event.toString()); } @Override public boolean onSingleTapUp(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapUp: " + event.toString()); return true; } @Override public boolean onDoubleTap(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTap: " + event.toString()); return true; } @Override public boolean onDoubleTapEvent(MotionEvent event) { Log.d(DEBUG_TAG, "onDoubleTapEvent: " + event.toString()); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { Log.d(DEBUG_TAG, "onSingleTapConfirmed: " + event.toString()); return true; }}
更详细可以看下这两篇博客:
http://blog.csdn.net/xyz_lmn/article/details/16826669
http://blog.csdn.net/hpk1994/article/details/51224228
ScrollTo 、scrollBy
1、ScrollTo(int x, int y)、ScrollBy(int x, int y)
ScrollBy默认也是调用的ScrollTo方法:
public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
mScrollX 记录的是View的左边缘和View内容的左边缘之间的距离,mScrollY 记录的是View的上边缘和View内容的上边缘之间的距离
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(); } } }
看源码scrollTo(int x, int y)中将x值赋给了mScrollX ,y赋给了mScrollY ,所以scrollTo是相对于View左边缘的绝对滑动,scrollBy是相对滑动,另外要注意的是:scrollTo和scrollBy是对View内容的滑动而不是对View的滑动。
Scroller常用方法:
Scroller类并不会控制View进行滑动,它只是View滑动的辅助类,负责计算View滑动的一系列参数:
调用Scroller的startScroll()方法并不会有任何滑动行为,这里的滑动指的是View内容的滑动而不是View的滑动,来看startScroll方法的源码:
public void startScroll(int startX, int startY, int dx, int dy, int duration) { mMode = SCROLL_MODE; mFinished = false; mDuration = duration; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mStartX = startX; mStartY = startY; mFinalX = startX + dx; mFinalY = startY + dy; mDeltaX = dx; mDeltaY = dy; mDurationReciprocal = 1.0f / (float) mDuration; }
可以看到只是一些赋值操作,没有任何滑动操作,所以如果想让View内容滑动,还需要invalidate()的参与,如:
private Scroller mScroller = new Scroller(context); ... public void zoomIn() { // Revert any animation currently in progress mScroller.forceFinished(true); // Start scrolling by providing a starting point and // the distance to travel mScroller.startScroll(0, 0, 100, 0,3000); // Invalidate to request a redraw invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // Get current x and y positions int currX = mScroller.getCurrX(); int currY = mScroller.getCurrY(); scrollTo(currX, currY); invalidate(); } }
看下效果:
流程是这样的:首先在startScroll中设置各种滑动信息,这时并没有进行滑动,当调用下面的invalidate时,View会进行重绘,重绘时又会调用View中的computeScroll()方法,View中的computeScroll()是个空实现,需要我们自己实现,在computeScroll()中,我们先通过computeScrollOffset判断是否滑动完成,如果没完成,通过mScroller.getCurrX()、mScroller.getCurrY()得到滑动的位置,然后通过scrollTo(currX, currY)来实现滑动,此时完成了一次滑动,然后调用invalidate()方法继续重绘,继续滑动到新位置,直到滑动完成。
OverScroller
OverScroller大部分API和Scroller是一样的,只是多了一些对滑动到边缘时的处理方法:
OverScroller因为和Scroller非常类似,而且增加了回弹支持,所以大部分情况下我们都可以使用OverScroller。
下一篇通过模仿一下QQ侧滑菜单例子来实践一下上述知识点:Android仿QQ侧滑菜单
- Android View滑动相关的基础知识点
- android View的相关知识点
- Android View相关知识点
- Android View基础知识点
- Android Binder相关的一些基础知识点.
- Android View的滑动
- Android View的滑动
- Android绘图基础之实现View滑动的方法
- 自定义View基础(二)View的滑动
- Android view 相关一些基础
- Smali相关的基础知识点
- Android中View的滑动
- Android 中 View 的滑动
- View相关知识点
- View的工作原理一(基础知识点)
- 【Android】Android View的滑动实现
- Android Edittext相关的知识点
- android横向滑动选择的view
- -source 1.6 中不支持 lambda 表达式(请使用 -source 8 或更高版本以启用 lambda 表达式)
- redis伪集群搭建
- CAD数据导入ArcGIS方法小结
- IE版本对应值
- MyCat--开源分布式数据库中间件
- Android View滑动相关的基础知识点
- NetBeans的格式化代码风格,编辑代码风格,统一代码格式
- esp8266采用AT方式建立udp客户端
- J2EE JSP Java的区别
- Spark之分层抽样
- opengl
- 陕鼓-肥水流到外人
- 拓扑排序 Fox And Names : CodeForces
- Java File 类的使用方法详解