Android知识点汇总--第二篇
2016-08-25 15:45
302 查看
View基础
View的位置参数:top,left,right,bottom。都是相对于View的父容器来说的。Android3.0以后增加了:x,y,translationX,translationY。x,y为View左上角坐标,translationX,translationY是View左上角相对于父容器的偏移量。
在点击事件中:
getX/getY返回当前View左上角的x和y坐标。getRawX/getRawY返回手机屏幕左上角x/y坐标。
最小滑动距离:
ViewConfiguration.get(getContext()).getScaledTouchSlop()
VelocityTracker/GestureDetector/Scroller
VelocityTracker:在View的onTouchEvent方法中追踪当前单击事件的速度:
VelocityTracker vt = VelocityTracker.obtain(); vt.addMovement(event); ...... vt.computeCurrentVelocity(1000);//计算1000ms之内移动的像素数 int xVt = (int)vt.getXVelocity();//x方向的速度 int yVt = (int)vt.getYVelocity(); ...... //在不需要使用的时候,调用clear方法重置并回收内存 vt.clear(); vt.recycler();
GestureDetector:
可以用来检测用户的单击、滑动、长按、双击行为。可以实现OnGestureListener或者onDoubleTapListener来监听双击行为。如果只监听滑动事件,直接在onTouchEvent方法中处理就可以了,如果要监听双击行为,就需要使用GestureDetector。
创建GestureDetector对象以后,在View的onTouchEvent方法中添加:
boolean consume = mGestureDetector.onTouchEvent(event); return consume;
Scroller:
Scroller本身无法让View弹性滑动,需要和View的computeScroll方法配合使用才能共同完成。通过scrollTo和scrollBy来完成,它不断让View重绘,而每一次重绘距滑动起始时间会有一个时间间隔,通过这个时间间隔Scroller就可以得出View当前的滑动距离,再通过scrollTo来完成滑动。
scrollBy内部调用scrollTo方法,scrollTo方法实现了基于所传递参数的绝对滑动。这两个方法只改变View内容的位置而不改变View在布局中的位置。
从左—–>右滑动:mScrollX为负值。
从上—–>下滑动:mScrollY为负值。
弹性滑动
Scroller/动画/延时策略采用动画来实现滑动动画:
ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000); animator.addUpdateListener(new AnimatorUpdateListener(){ @Override public void onAnimationUpdate(ValueAnimator animator){ float fraction = animator.getAnimatedFraction(); mView.scrollTo(startX+(int)(deltaX*fraction),0); } });
延时策略:
通过发送一系列延时消息从而达到滑动效果。可以使用Handler,postDelayed,sleep来完成。
View事件分发机制
涉及到三种主要方法:dispatchTouchEvent/onInterceptTouchEvent/onTouchEvent。public boolean dispatchTouchEvent(MotionEvent ev){ boolean consume = false; if(onInterceptTouchEvent(ev)){ //根ViewGroup是否拦截 consume = onTouchEvent(ev); }else{ consume = child.dispatchTouchEvent(ev); } return consume; }
优先级:OnTouchListener>onTouchEvent>OnClickListener
点击事件传递过程:Activity->Window->View。
如果子View的onTouchEvent返回false,则会调用父容器的onTouchEvent方法。
ViewGroup默认不拦截任何事件。
View没有onInterceptTouchEvent方法,一旦有点击事件给它,那么它的onTouchEvent方法会被调用。
View的onTouchEvent默认都会消耗事件,除非它的clickable属性为false。
View的enable属性不影响onTouchEvent的默认返回值。
事件传递过程总是先传递给父元素,然后通过父元素分发给子View。在子元素中可以通过requestDisallowInterceptTouchEvent方法敢于父元素的分发过程,ACTION_DOWN事件除外。对于ACTION_DOWN事件,ViewGroup总是会调用自己的onInterceptTouchEvent方法来询问是否要拦截事件。
ViewGroup决定拦截事件后,后续的点击操作会默认交给它处理并且不再调用它的onInterceptTouchEvent方法。如果我们想提前处理所有的点击事件,要选择dispatchTouchEvent方法,只有这个方法会每次都会调用,前提是点击事件能够传递到当前的ViewGroup。
事件传递顺序:上级->下级。
事件处理顺序:下级->上级。
事件传递时候先调用dispatchTouchEvent方法,再执行onInterceptTouchEvent方法。返回值true,表示拦截不继续。
事件处理都是调用onTouchEvent方法,返回true,表示处理了,不用审核了。
初始情况下,返回值都是false。
滑动冲突解决方案
外部拦截法和内部拦截法外部拦截法:
重写父容器的onInterceptTouchEvent方法。在ACTION_DOWN和ACTION_UP这两种情况下需要返回false,在ACTION_MOVE方法中根据条件判断父容器是否需要拦截。
内部拦截法:
父容器不拦截任何事件,所有事件传递给子元素。需要配合requestDisallowInterceptTouchEvent方法才能正常工作。在ACTION_DOWN的时候,子元素需要调用parent.requestDisallowInterceptTouchEvent(true)。
父元素也要默认拦截除了ACTION_DOWN以外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截所需事件。一旦父容器拦截了ACTION_DOWN事件,所有的事件都无法传递到子元素中。
ViewRoot和DecorView
ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的measure、layout、draw都是通过ViewRoot来完成的。在ActivityThread中,当Activity对象被创建完成后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,将ViewRootImpl和DecorView之间建立关联。View的绘制
View工作流程指measure/layout/draw三个流程。View的最终大小是在layout阶段确定的。
直接继承View的自定义控件需要重写onMeasure方法并设置wrap_content时的自身大小,否则在布局中使用wrap_content相当于使用match_parent。
解决View测量的四种方法:
1. onWindowFocusChanged方法
View已经初始化完毕了,当Activity窗口得到和失去焦点的时候都会调用一次。
2. view.post(runnable)
通过post也可以将一个runnalbe投递到消息队列的尾部,然后等待Looper调用此runnable的时候,View已经初始化好了。
protected void onStart(){ super.onStart(); view.post(new Runnable(){ @Ovriride public void run(){ int width = view.getMeasureWidth(); int height = view.getMeasureHeight(); } }); }
ViewTreeObserver
使用它的众多回调可以完成这个功能。可以通过OnGlobalLayoutListener这个接口。当View树的状态发生改变或者View树内部的View的可见性发生改变时,onGlobalLay
4000
out方法将会被回调。
protected void onStart(){ super.onStart(); ViewTreeObserver observer = view.getViewTreeObserver(); observer.addOnGloalLayoutListener(new OnGlobalLayoutListener(){ @Override public void onGlobalLayout(){ view.getViewTreeObserver().removeGlobalOnLayoutListener(this); int width = view.getMeasureWidth(); int height = view.getMeasureHeight(); } }); }
view.measure(int widthMeasureSpec,int heightMeasureSpec)
通过手动测量。
Layout的作用是ViewGroup用来确定子元素位置的,在layout方法中确定View本身的位置,在onLayout方法中确定所有子元素的位置。
View的绘制过程遵循以下几步:
绘制背景 background.draw(canvas)
绘制自己 onDraw
绘制children dispatchDraw,dispatchDraw会遍历所有子元素的draw方法。
绘制装饰 onDrawScrollBars
自定义View的方法
需要注意的一些问题:1.让View支持wrap_content。
2.直接继承View的控件,如果不在draw方法中处理padding,那么padding属性不起作用;如果直接继承ViewGroup,需要在onMeasure和onLayout中考虑padding和子元素的margin对其造成的影响。
3.在View的内部提供了post系列的方法,可以替代Handler。
4.View中的动画和线程,在onDetachedFromWindow中停止比较好。
5.View中存在滑动嵌套,需要考虑滑动冲突问题。
相关文章推荐
- Android Java 框架基础[知识点汇总]
- android编程中的琐碎知识点汇总(3)
- Android RecyclerView源码与知识点汇总
- Android 小知识点汇总(更新中)
- Android小知识点汇总
- Android知识点汇总--第一篇
- Android开发之实用小知识点汇总-1
- android知识点汇总
- Android 琐碎知识点汇总
- android编程中的琐碎知识点汇总(4)
- 【转】Android一些知识点汇总
- Android知识点汇总
- Android开发之实用小知识点汇总-2
- android EditText相关的知识点汇总
- android编程中的琐碎知识点汇总(2)
- Android知识点汇总
- android知识点记录汇总(不断更新中)
- Android常用知识点汇总(不断更新)
- 常用Android布局学习知识点汇总