自定义View
view的事件体系
- 基础
- view的位置由
top
,left
,right
,bottom
决定,这些坐标都是相对view的父容器来说的,- 在View平移的过程中,
top
,left
代表的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x
,y
,translationX
,translationY
- 在View平移的过程中,
- MotionEvent和TouchSlop
- 通过MotionEvent对象我们可以获得点击事件发生的x和y坐标,
getX/getY
, 和getRawX/getRawY
,其中getX/getY
返回的是相对于当前view左上角的x和y坐标,而getRawX/getRawY
返回的是相对于手机屏幕左上角的x和y坐标
- 通过MotionEvent对象我们可以获得点击事件发生的x和y坐标,
- VelocityTracker,GestureDetector和Scroller
- 使用GestureDetector的情景:如果只是监听滑动相关,自己在
onTouchEvent
中实现即可,如果要监听双击这种行为,才使用GestureDetector
- 使用GestureDetector的情景:如果只是监听滑动相关,自己在
- view的位置由
- view的滑动
- 使用scrollTo/scrollBy
scrollTo
实现了当前位置的绝对滑动,scrollBy
实现了当前位置的相对滑动scrollTo
scrollBy
只能改变View内容的位置而不能改变View在布局中的位置- 关于
mScrollX
,mScrollY
, 位置改变需注意
- 通过动画给View施加平移效果
- 主要操作View的
translationX
和translationY
属性 - View动画是对View的影像做操作,并不能真正改变View的位置参数,包括宽高,如果希望动画后状态得以保留还必须将fillAfter设置为true
- 主要操作View的
- 使用属性动画
- 荣国改变View的LayoutParams来使得View重新布局
- 使用scrollTo/scrollBy
- View的弹性滑动
- 使用scrollTo
- 使用Scroller
- 通过动画
onAnimationUpdate
方法:- 模仿Scroller,通过改变百分比配合scrollTo方法来完成View的滑动,注意只能是View的内容而非View本身
- 使用延时策略
- 使用Handler#postDelayed
- 使用Thread#sleep
- 使用scrollTo
View的事件分发机制
-
点击事件的传递规则:
-
public boolean dispatchTouchEvent(MotionEvent ev) { boolean consume = false; if (onInterceptTouchEvent(ev)) { consume = onToucnEvent(ev); } else { consume = child.dispatchTouchEvent(ev); } return consume;}复制代码
-
当一个view需要处理事件时:
- 优先级:OnTouchListener>onTouchEvent>OnclickListener
- 传递顺序:Activity->Window->View
- 如果底层View的
onTouchEvent
返回false,则父容器的onTouchEvent
将会被调用,如果所有元素都不处理这个事件,那么Activity的onTouchEvent
将会被调用
-
View的滑动冲突
view的工作流程
-
ViewRoot和DecorView的概念
- View的三大流程均是通过ViewRoot来完成的。View的绘制流程从ViewRoot的performTraversals开始,依次调用
performMeasure
,performLayout
,performDraw
三个方法
- View的三大流程均是通过ViewRoot来完成的。View的绘制流程从ViewRoot的performTraversals开始,依次调用
-
measure过程
-
MeasureSpec
- MeasureSpc代表32位int值,高2位代表SpecMode,低30位代表SpecSize
- SpecMode类别:EXACTLY对应match_parent,AT_MOST对应wrap_content
- 对于普通的View,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定
-
onMeasure
-
setMeasuredDimension
会设置view的宽高 -
直接继承View的自定义控件需要重写
onMeasure
方法并设置wrap_content时的自身大小,否则在布局中使用wrap_content就相当于使用match_parent//只需要给View指定一个默认的内部宽高(mWidth, mHeight)protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(mWidth, mHeight); } else if (widthSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(mWidth, heightSpecSize); } else if (heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpecSize, mHeight); }}复制代码
-
measure完成后,通过
getMeasuredWidth/Height
方法就可以获得View的测量宽高,比较好的习惯是在onLayout
方法中获取View的测量宽高或最终宽高 -
在activity中获得View的宽高
- Activity/View#onWindowFocusChanged
- view.post(runnable)
- ViewTreeObserver
- view.measure
-
-
-
layout过程
-
draw过程
- 步骤
- 绘制背景background.draw(canvas)
- 绘制自己onDraw
- 绘制children(dispatchDraw)
- 绘制装饰onDrawScrollBars
- 如果我们自定义控件继承ViewGroup并且本身并需要通过
onDraw
来绘制内容时,我们需要显式地关闭WILL_NOT_DRAW这个标记位
- 步骤
自定义View
-
分类:
- 继承View重写onDraw方法,主要用于实现一些不规则效果
- 继承ViewGroup派生特殊的Layout,主要用于实现自定义布局
- 继承特定的View(比如TextView)
- 继承特定的ViewGroup(比如LinearLayout)
-
需要实现:
-
支持wrap_content
-
支持padding:只要在
onDraw
方法中考虑一下padding即可, -
提供自定义属性:
-
在values目录下创建自定义属性的XML,比如attrs.xml,
格式有reference(是指资源id), dimension(指尺寸),string,integer,boolean
-
在View的构造方法中解析自定义属性的值并做相应的处理
public CirecleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleView); mColor = a.getColor(styleable.CircleView_circle_color, Color.RED); a.recycle(); init();}复制代码
-
在布局文件中使用自定义属性
注意:必须在布局文件中添加schemas声明:
xmlns:app=http://schemas.android.com/apk/res-auto复制代码
-
-
不要在View中使用Handler
-
View中如果有线程或者动画,需要在
onDetachedFromWindow
方法中及时停止,防止内存泄漏
参考:《Android开发艺术探索》
-