一、
1、Activity页面构成元素
- 1)在activity 中 通过 setContentView() 方法设置为根布局。在每一个Activity 中 都包含一个Window 对象,它由 PhoneWindow来实现
- 2)PhoneWindow 将一个 DecorView 设置为整个应用窗口的根View。
- 3)DecorView,由TitleView 和ContentView组成, 前者承载的是一个Actionbar,后者承载的是一个FrameLayout,
2、MotionEvent和TouchSlop
- 1)手指接触屏幕后 会产生以下的事件:
ACTION_DOWN // 收支接触ACTION_MOVE // 手指在屏幕上移动ACTION_UP //手指从屏幕松开ACTION_CANCEL //取消复制代码
-
2)MotionEvent 对象获取的 点击的 x 和 y ,
①.使用 getX / getY 获取的是相对于当前View左上角的x和y, ②.而 getRawX / getRawY 获取的是相对于手机屏幕左上角的坐标。 -
3)TouchSlop:是系统所能识别的最小滑动距离,小于它则视未发生滑动,在不同的设备上获取的值不同。通过:
ViewConfiguration.get(getContext()).getScaledTouchSlop() //获得复制代码
3、VelocityTracker、GestureDetector和Scroller
- 1)VelocityTracker:速度追踪,用于追踪滑动过程中的速度,包括水平和竖直速度。
//1.在 onTouchEvent 方法中追踪当前事件的速度VelocityTracker tracker = VelocityTracker.obtain();tracker.addMovement(event);//2.获取当前速度tracker.computeCurrentVelocity(1000);//计算速度int xVelocity = (int) tracker.getXVelocity();int yVelocity = (int) tracker.getYVelocity();//3.在不需要的时候重置回收内存tracker.recycle();复制代码
- 2)GestureDetector:用于检测单击、滑动、长按、双击等手势。 首先要实现 GestureDetector.OnGestureListener接口,如果需要双击,则需实现 GestureDetector.OnDoubleTapListener 接口;
//设置监听mGestureDetector = new GestureDetector(this);//避免长按后无法拖动,自己测试时发现不设置,长按后也可以拖动mGestureDetector.setIsLongpressEnabled(false);复制代码
- 3)Scroller:弹性滑动,可是实现有过度效果的滑动,View 的 ScrollTo/ScrollBy 都是瞬间滑动完成的。
4、View 的滑动
- 1)View的滑动主要有如下三种方式:
- scrollTo /scrollBy :适合对view 的内容改变;
- 动画: 主要用于没有交互的View 和实现复杂的动画效果;
- 改变布局参数:操作稍微复杂,适合有交互的View 。
- 2)View 的 ScrollTo/ScrollBy 方法
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(); } } } public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }复制代码
其中 scrollBy 调用的是 scrollTo,它实现了使用当前位置的相对滑动,而scrollTo 是基于所传参数的绝对滑动.
- 3)使用动画 通过动画为View 添加平移效果,View 的 tanslationX 和 tanslationY 属性,可以采用传统的动画和属性动画。
- 4)改变布局参数 通过改变View 的LayoutParams 使得 View 重新布局实现滑动。
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mButton.getLayoutParams();params.width += 100;params.leftMargin += 100;mButton.setLayoutParams(params); // 或者 mButton.requestLayout();复制代码
5、弹性滑动
为了避免 滑动的生硬,可以采用弹性滑动,提高用户体验。
这里主要有 :Scroller、动画、延时三种方式。- 1)Scroller 的典型使用,主要是 invalidate方法起的作用。
Scroller mScroller = new Scroller(context);/** * 滑动到指定位置 * * @param destX X 滑动距离 * @param destY Y 滑动距离 */private void smoothScrollTo(int destX, int destY) { //滑动起点X int scrollX = getScrollX(); //滑动起点Y int scrollY = getScrollY(); //1000 ms内慢慢滑向 (destX,destY) mScroller.startScroll(scrollX, scrollY, destX, destY, 1000); //重绘 invalidate();} /** * 使View 不断重绘 */@Overridepublic void computeScroll() { /** * computeScrollOffset 方法通过时间流逝百分比计算 scrollX和scrollY * 返回true 表示滑动未结束 */ if (mScroller.computeScrollOffset()) { //滑动到当前位置,通过小幅度滑动实现弹性滑动 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //再次重绘 postInvalidate(); }}复制代码
- 2)对于延时达到弹性滑动,主要是利用 了Handler 或者 View 的 postDelayed 方法,或者线程的 sleep方法。
6、View 的事件分发机制
- 1)所有的Touch事件都封装到 MotionEvent 里面;
- 2)事件处理包括三种情况,分别为:传递—-dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费—-onTouchEvent()函数和OnTouchListener;
- 3)事件类型分为 ACTION_DOWN, ACTION_UP, ACTION_MOVE , ACTION_POINTER_DOWN, ACTION_POINTER_UP , ACTION_CANCEL 等,每个事件都是以 ACTION_DOWN 开始 ACTION_UP 结束。
用下面伪代码表示事件分发过程及其关系:
//事件分发public boolean dispatchTouchEvent(MotionEvent event) { boolean consume = false; //是否被拦截 if (onInterceptTouchEvent(event)) { //被拦截,处理事件 consume = onTouchEvent(event); } else { //未被拦截,向下分发 consume = childView.dispatchTouchEvent(event); } return consume;}复制代码
1、activity --->ViewGroup --->view 正常流程:
- 1)当activity dispatchTouchEvent() 返回 true :代表事件停止分发,activity 的onTouchEvent()方法不执行。其子view也接受不到事件。
- 2)ViewGroup onInterceptTouchEvent() 返回ture时,onTouchEvent() 也返回 true时;
ViewGroup
①、 ViewGroup oninterceptTouchEnent 返回 ture时,表示:传递给子View的事件被拦截了, ViewGroup onTouchEvent() 返回 true时,表示:该事件被VieWGroup自身消费了,不传递给父View的onTouch方法中处理了。 代码:EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWNEmptyViewGroup: onTouchEvent--->ACTION_DOWN...EmptyViewGroup: onTouchEvent--->ACTION_MOVE...EmptyViewGroup: onTouchEvent--->ACTION_UP复制代码
②、
ViewGroup oninterceptTouchEnent 返回 ture时,表示:传递给子View事件被拦截了, ViewGroup onTouchEvent() 返回 false时,表示:ViewGroup也不处理此事件,交给上层父View(avtivity)的OnTouchEvent()方法处理。 代码://viewGroup只消费 ACTION_DOWN 事件EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWNEmptyViewGroup: onTouchEvent--->ACTION_DOWN//activity 将事件消费DemoActivity: onTouchEvent--->ACTION_DOWN...DemoActivity: onTouchEvent--->ACTION_MOVE...DemoActivity: onTouchEvent--->ACTION_UP复制代码
③、 ViewGroup onInterceptTouchEvent 返回 false时,表示事件传递给子View,不拦截。
ViewGroup onTouchEvent() 返回 false时,ViewGroup也不处理此事件,交给上层父View(avtivity)的OnTouchEvent()方法处理。 View onTouchEvent() 返回 true: 该子View消费了此事件。不传递到ViewGroup的OnTouchEvent()方法中。EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWNEmptyView: onTouchEvent--->ACTION_DOWNEmptyViewGroup: onInterceptTouchEvent--->ACTION_MOVEEmptyView: onTouchEvent--->ACTION_MOVE...EmptyViewGroup: onInterceptTouchEvent--->ACTION_UPEmptyView: onTouchEvent--->ACTION_UP复制代码
④、 ViewGroup onInterceptTouchEvent 返回 false时,表示事件传递给子View,不拦截。
ViewGroup onTouchEvent() 返回 false时,ViewGroup也不处理此事件,交给上层父View(avtivity)的OnTouchEvent()方法处理。 View onTouchEvent() 返回 false: 该子View不消费了此事件。传递到ViewGroup的OnTouchEvent()方法中。EmptyViewGroup: onInterceptTouchEvent--->ACTION_DOWNEmptyView: onTouchEvent--->ACTION_DOWNEmptyViewGroup: onTouchEvent--->ACTION_DOWNDemoActivity: onTouchEvent--->ACTION_DOWNDemoActivity: onTouchEvent--->ACTION_MOVE...DemoActivity: onTouchEvent--->ACTION_UP复制代码
由于activity作为顶级的View,当activity 中所有得子View 都不消费onTouchEvent()事件时,ativity的OnTouchEvent() 无论返回true/false。该activity都会消费用户触发的事件。在onTouchEvent()中。