View的基础知识
-
MotionEvent 对象我们可以得到点击事件发生的x和y坐标.为此,系统提供了两组方法:getX/getY和getRawX/getRawY.他们的区别很简单 getX/Y返回的是相对于当前View左上角的x/y的坐标,而getRawX/getRawY返回的是相当于手机屏幕左上角的x/y坐标.
-
TouchSlop是系统所能识别的被认为滑动的最小距离.这个是常量和设备有关,不同设备值可能不同.
-
TouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
-
VelocityTracker 速度跟踪 追踪滑动的速度
-
VelocityTracker vt=VelocityTracker .obtain();
-
vt.addMovement(event);
-
vt.computeCurrentVelocity(1000);
-
int x = (int) vt.getXVelocity();
-
int y = (int) vt.getYVelocity();
-
在使用完以后回收内存 vt.clear(); vt.recycle();
-
GestureDetector 手势监测 用于辅助检测用户的单击滑动长按双击等行为
View的滑动
-
实现滑动方式有三种:(1)通过自身的ScrollTo/ScrollBy实现滑动,(2)通过动画给View添加平移效果(3)通过改变VIew的LayoutParams 是的重新布局来实现滑动.
-
ScrollTo/ScrollBy实现滑动
-
public void scrollTo(int x,int y){} x: the x postion to scroll to; y: the y postion to scroll to
-
public void scrollBy(int x ,int y ){ scrollTo(mScrollX+x,mScrollY + y );} x:the amount of pixels to scroll by horizontally; y : the amount of pixels to scroll by Vertically;
-
使用动画 包括 View动画和属性动画(动画并不能真正改变View的位置)
-
View动画
-
属性动画
-
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();
-
fillAfter flase: 动画完成View回到原来的位置 true: 动画完成View到达指定的位置
-
改变布局参数
-
MarginLayoutParams params = (MarginLayoutParams) mButton1.getLayoutParams();
-
params.width + =100;
-
params.leftMargin +=100;
-
mButton1.requestLayout();
-
//或者 mButton1.setLayoutParams(params);
-
各种滑动方式的对比
-
ScrollTo/ScrollBy: 操作简单.适合对View内容的滑动
-
动画: 操作简单主要适用于没有交互的View和复杂的动画效果
-
改变布局: 操作稍微复杂,适用于有交互的View
View的事件分发机制
- boolean dispatchTouchEvent(MotionEvent event);//是否消费了事件
- boolean onIntercepteTouchEvent(MotionEvent event)//是否拦截事件
- boolean onTouchEvent(MotionEvent ev);//事件处理
- 三者关系的伪代码
-
public boolean dispatchTouchEvent(MotionEvent ev){
-
boolean consume = false;
-
if(onIntercepteTouchEvent(ev)){
-
consume = onTouchEvent(ev);
-
} else {
-
consume = child.dispatchTouchEvent(ev);
-
}
-
return consume;
-
}
- 事件优先级 OnTouchListener(onTouch)>onTouchEvent>onClickListener(onClick);
- ViewGroup默认不拦截任何事件,默认返回false;
- View没有onInterceptTouchEvent方法,一旦有事件传给他,它会立即调用onTouchEvent
- View的onTouchEvent默认都会消费事件(返回true),除非他是不可点击的(clickable和longclickable同时为false) View的longClickable默认都是false Button的clickable为true,TextView的clickable默认为false.
- onClick发生的前提是View是可点击的&& 收到down和up的事件.
事件分析的源码解析
- decor view 它一般是当前界面的底层容器 Activity.getWindow.getDecorView();可以获得
- 事件传递的过程Activity->Window->dicorView>根View(ViewGroup)
- 顶级View(ViewGroup)的事件分发:调用dispatchTouchEvent如果ViewGroup拦截即onInterceptEvent返回true.则事件由Viewgroup处理,如果他的onTouchListener被设置则onTouch被调用否则onTouchEvent被调用.如果Viewgroup不拦截则被传到子View 然后调用dispatchTouchEvent.....如此循环
事件冲突的解决
- 解决方案一般有两种:外部拦截法和内部拦截法.
View的工作流程 measure->layout->draw
-
measure:
-
View的measure过程 :由一个measure方法完成(final类型不可重写),它会调用View的onMeasure方法
-
layout 主要就是一个setFrame(int left,int top,int right,int bottom);即设置位置和setChildFrame(View childView,int left,int top,int right,int bottom);
-
draw 分四步
-
绘制背景 background.draw(canvas)
-
绘制自己 onDraw
-
绘制子布局 dispatchDraw
-
绘制装饰 onDrawScrollBars
网友评论