扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
开发自定义控件的步骤:
创新互联专业为企业提供鹿泉网站建设、鹿泉做网站、鹿泉网站设计、鹿泉网站制作等企业网站建设、网页设计与制作、鹿泉企业网站模板建站服务,十年鹿泉做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
1、了解View的工作原理
2、 编写继承自View的子类
3、 为自定义View类增加属性
4、 绘制控件
5、 响应用户消息
6 、自定义回调函数
一、View结构原理
Android系统的视图结构的设计也采用了组合模式,即View作为所有图形的基类,Viewgroup对View继承扩展为视图容器类。
View定义了绘图的基本操作
基本操作由三个函数完成:measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。具体操作如下:
1、measure操作
measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:
(1)onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
2、layout操作
layout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:
(1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;
(2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;
3、draw操作
draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法,因为其内部定义了绘图的基本操作:
(1)绘制背景;
(2)如果要视图显示渐变框,这里会做一些准备工作;
(3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示(比如TextView在这里实现了绘制文字的过程)。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法,因此只需要告诉子view绘制自己就可以了,也就是下面的dispatchDraw()方法;
(4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;
(5)如果需要(应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框;
(6)绘制滚动条;
从上面可以看出自定义View需要最少覆写onMeasure()和onDraw()两个方法。
二、View类的构造方法
创建自定义控件的3种主要实现方式:
1)继承已有的控件来实现自定义控件: 主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。
2)通过继承一个布局文件实现自定义控件,一般来说做组合控件时可以通过这个方式来实现。
注意此时不用onDraw方法,在构造广告中通过inflater加载自定义控件的布局文件,再addView(view),自定义控件的图形界面就加载进来了。
3)通过继承view类来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方式。
三、自定义View增加属性的两种方法:
1)在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。
案例:实现一个带文字的图片(图片、文字是onDraw方法重绘实现)
public class MyView extends View {
private String mtext;
private int msrc;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
int resourceId = 0;
int textId = attrs.getAttributeResourceValue(null, "Text",0);
int srcId = attrs.getAttributeResourceValue(null, "Src", 0);
mtext = context.getResources().getText(textId).toString();
msrc = srcId;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.RED);
InputStream is = getResources().openRawResource(msrc);
Bitmap mBitmap = BitmapFactory.decodeStream(is);
int bh = mBitmap.getHeight();
int bw = mBitmap.getWidth();
canvas.drawBitmap(mBitmap, 0,0, paint);
//canvas.drawCircle(40, 90, 15, paint);
canvas.drawText(mtext, bw/2, 30, paint);
}
}
布局文件:
?xml version="1.0" encoding="utf-8"?
LinearLayout xmlns:android=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
com.example.myimageview2.MyView
android:id="@+id/myView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
Text="@string/hello_world"
Src="@drawable/xh"/
/LinearLayout
属性Text, Src在自定义View类的构造方法中读取。
2)通过XML为View注册属性。与Android提供的标准属性写法一样。
案例: 实现一个带文字说明的ImageView (ImageView+TextView组合,文字说明,可在布局文件中设置位置)
public class MyImageView extends LinearLayout {
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
int resourceId = -1;
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.MyImageView);
ImageView iv = new ImageView(context);
TextView tv = new TextView(context);
int N = typedArray.getIndexCount();
for (int i = 0; i N; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.MyImageView_Oriental:
resourceId = typedArray.getInt(
R.styleable.MyImageView_Oriental, 0);
this.setOrientation(resourceId == 1 ? LinearLayout.HORIZONTAL
: LinearLayout.VERTICAL);
break;
case R.styleable.MyImageView_Text:
resourceId = typedArray.getResourceId(
R.styleable.MyImageView_Text, 0);
tv.setText(resourceId 0 ? typedArray.getResources().getText(
resourceId) : typedArray
.getString(R.styleable.MyImageView_Text));
break;
case R.styleable.MyImageView_Src:
resourceId = typedArray.getResourceId(
R.styleable.MyImageView_Src, 0);
iv.setImageResource(resourceId 0 ?resourceId:R.drawable.ic_launcher);
break;
}
}
addView(iv);
addView(tv);
typedArray.recycle();
}
}
attrs.xml进行属性声明, 文件放在values目录下
?xml version="1.0" encoding="utf-8"?
resources
declare-styleable name="MyImageView"
attr name="Text" format="reference|string"/attr
attr name="Oriental"
enum name="Horizontal" value="1"/enum
enum name="Vertical" value="0"/enum
/attr
attr name="Src" format="reference|integer"/attr
/declare-styleable
/resources
MainActivity的布局文件:先定义命名空间 xmlns:uview="" (com.example.myimageview2为你
在manifest中定义的包名)
然后可以像使用系统的属性一样使用:uview:Oriental="Vertical"
LinearLayout xmlns:android=""
xmlns:uview=""
xmlns:tools=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /
com.example.myimageview2.MyImageView
android:id="@+id/myImageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
uview:Text="这是一个图片说明"
uview:Src="@drawable/tw"
uview:Oriental="Vertical"
/com.example.myimageview2.MyImageView
/LinearLayout
四、控件绘制 onDraw()
五、
六:自定义View的方法
onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure() 检测View组件及其子组件的大小
onLayout() 当该组件需要分配其子组件的位置、大小时
onSizeChange() 当该组件的大小被改变时
onDraw() 当组件将要绘制它的内容时
onKeyDown 当按下某个键盘时
onKeyUp 当松开某个键盘时
onTrackballEvent 当发生轨迹球事件时
onTouchEvent 当发生触屏事件时
onWindowFocusChanged(boolean) 当该组件得到、失去焦点时
onAtrrachedToWindow() 当把该组件放入到某个窗口时
onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法
先上效果图
源码
单点拖动图片对图片进行平移操作。双手缩放图片大小和旋转图片到一定的角度。图片缩放的时候 不能大于最大的缩放因子和小于最小的缩放因子。大于最大缩放因子或者小于最小缩放因子需要对图像进行回弹。图片旋转的角度只能为90度的倍数,不满足90度要进行回弹。图片回弹要一个渐变的效果。
大体思路: 首先,Android中提供了Matrix类可以对图像进行处理。其次,要显示一张图片最容易想到的就是ImageView。回弹要求渐变的过程,可以通过属性动画进行设置。所以大体的思路是:继承ImageView,重写onTouchEvent()方法,判断事件类型,在对应的事件使用Matrix对图像进行变换。
Matrix是一个已经封装好的矩阵,最重要的作用就是对坐标点进行变换。
举个栗子:
1.某个点(x0,y0,1)通过单位矩阵E映射得到的点还是(x0,y0,1)。
3.点(x0,y0,1)通过矩阵T映射得到的点就会做如下的变换
可以看到点(x0,y0,1)经过T矩阵在x轴方向上平移了dx,在y轴方向上平移了dy。
通过以上的变换可以得到具体的思路: 我们维护一个图像对应的矩阵mCurrentMatrix,该矩阵主要是对ImageView中的图像的各个点进行映射。ImageView在容器位置摆放完成之后,置mCurrentMatrix矩阵为单位矩阵。当onTouchEvent()方法中触发单点触控并且手指进行平移的时候,调用矩阵mCurrentMatrix的postTranslate(dx,dy),对mCurrentMatrix进行变换。当手指抬起,利用变换结束后的矩阵对图像的各个点进行映射,从而得到平移变换后的图像。同理可得,在两只手指进行缩放旋转的时候,我们对矩阵mCurrentMatrix进行各种变换,当缩放旋转的事件结束再利用变换完的矩阵去映射图像的各个点,从而得到缩放、旋转后的图像。
安卓自定义View进阶 - Matrix原理
安卓自定义View进阶 - Matrix详解
首先理清事件的逻辑:
初始化图像大小和位置
缩放图像大小和控件大小自适应,平移图像中心和控件中心重合
onTouchEvent()函数
平移操作
将图像对应的矩阵进行变换。
缩放操作
mBoundRectF为记录图像边界的矩形。缩放的时候选取图像的中心进行缩放。
旋转操作
旋转的时候旋转的旋转中心也是图像的中心
图像中各个点的映射
调用ImageView的setImageMatrix(Matrix matrix)会让ImageView根据设置的matrix去重新绘制图像。
更新图像的矩形边界
获得图像的矩形,并根据矩阵映射矩形各个点的坐标。
缩放回弹
旋转回弹
一些计算方法
要求图像的变换是一个渐变的过程,很容易想到的就是属性动画。因为属性动画本身就是对值进行不断set的过程。而我们维护的矩阵也是一个值,所以很自然可以想到,如果得到回弹之前的矩阵的值以及回弹之后矩阵的值,就可以根据动画监听器中动画当前的系数值去改变矩阵的值。
对animator对象设置完监听器之后,就可以在手指抬起的时候调用属性动画的start()方法开启动画。
自定义可平移、缩放、旋转的控件主要点有两个方面:一是onTouchEvent()中判断平移、旋转、缩放的触发条件,平移位移量、缩放比例因子、旋转角度的计算。二是Matrix矩阵的应用。
每个view的坐标系原点为左上角那个点,水平方向为x轴,右正左负,竖直方向为y轴,下正上负。
canvas.drawColor //绘制区域涂上颜色(设置底色/蒙层)
canvas.drawCircle(float centerX(圆心X坐标),float centerY(圆心Y坐标),float radius(圆的半径,单位像素),Paint paint)
canvas.drawBitmap
canvas.drawRect(float left,float top,float right,float bottom,Paint paint) //画矩形
canvas.drawRect(RecF rect,Paint paint)
canvas.drawRect(Rect rect,Paint paint)
canvas.drawPoint(float x(点X轴坐标),float y(点Y轴坐标),Paint paint)//画点
点的大小 -paint.setStrokeWidth(width)
点的形状 -paint.setStrokeCap(cap)
ROUND(圆形),BUTT(平头),SQUARE(方头)
canvas.drawPoints()//批量画点
canvas.drawOval(float left(左边界点),float top(上边界点),float right(右边界点),float bottom(下边界点),Paint paint) //画椭圆
canvas.drawLine(float startX(起点X轴坐标),float startY(起点Y轴坐标),float stopX(终点X轴坐标),float stopY(终点X轴坐标),Paint paint) (setStyle对直线没有影响)
canvas.drawLines(批量画线)
canvas.drawRoundRect(float left,float top,float right,float bottom,float rx(圆角的横向半径),float ry(圆角的纵向坐标),Paint paint)//画圆角矩形
canvas.drawRoundRect(RectF rect,float rx, float ry,Paint paint)
canvas.drawArc(float left, float top, float right, float bottom, float startAngle(起始角度,顺时针为正,逆时针为负), float sweepAngle(弧形划过角度), boolean useCenter(是否连接到圆心), Paint paint) //绘制弧形或扇形 根据弧形所在椭圆进行绘制
canvas.drawPath() //通过描述路径的方式来绘制图形
path.addXxx() —添加子图形
path.addCircle(x,y,radius,dir(路径方向:顺时针/逆时针))
path.xxxTo —画线
path.lineTo()
path.rLineTo()
path.close() —封闭当前图形
path.setFillType(Path.FillType ft) //设置填充模式
canvas.drawBitmap(Bitmap bitmap,float left,float top,Paint paint);//画bitmap
canvas.drawBitmap(Bitmap bitmap,Rect src,RectF dst,Paint paint)
canvas.drawBitmap(Bitmap bitmap,Rect src,Rect dst,Paint paint)
canvas.drawBitmap(Bitmap bitmap,Matrix matrix,Paint paint)
canvas.drawText(String text,float x(起点x坐标),float y(起点y坐标),Paint paint) //绘制文字
Paint.setStyle //设置绘制模式
FILL 填充模式(默认)
STROKE 画线模式
FILL_AND_STROKE 既画线又填充
Paint.setStrokeWidth //设置线条宽度 (仅在style:Stroke、FILL_AND_STROLE下有效)
Paint.setTextSize //设置文字大小
Paint.setAntiAlias //设置抗锯齿开关
Paint.setTextSize(float textSize)//设置文字大小
Paint.setStrokeJoin(Paint.Join join) //设置拐角的形状
MITER//尖角(默认)
BEVEL//平角
ROUND//圆角
Paint.setStokeMiter(float miter)//设置MITER型拐角的延长线的最大值
设置颜色
直接设置颜色
Paint.setColor(int color)
Paint.setARGB(int a,int r,int g,int b)
Paint.setShader(Shader shader) //设置shader
LinearGradient 线性渐变
RadialGradient 辐射渐变
SweepGradient 扫描渐变
BitmapShader 用bitmap的像素来作为图形或文字的填充
ComposeShader 混合着色器,多个shader混合使用
Paint.setColorFilter(ColorFilter colorFilter) //设置颜色过滤
Paint.setXfermode(Xfermode xfermode) //以要绘制的内容为源图像,以View中已有内容作为目标图像,选取一个PorterDuff.Mode作为绘制内容的颜色处理方案。
色彩优化
Paint.setDither(boolean dither) //设置抖动来优化色彩深度降低时的绘制效果
Paint.setFilterBitmap(boolean filter) //设置双线性过滤优化Bitmap放大绘制的效果
可以理解为 由马赛克变成模糊状态
Paint.setPathEffect(PathEffect effect)//使用PathEffect设置形状的轮廓效果
CornerPathEffect//把所有的拐角变成圆角
DiscretePathEffect//把线条进行随机的偏离
DashPathEffect//使用虚线
PathDashPathEffect//使用一个Path来绘制虚线
SumPathEffect//组合效果
ComposePathEffect//组合效果,组合有先后顺序
Paint.setShadowLayer(float radius,float dx,float dy,int shadowColor)//添加阴影
Paint.setMaskFilter(MaskFilter maskfilter)//在绘制层上方的附加效果
BlurMaskFilter //模糊效果
new BlurMaskFilter(float radius(模糊范围),BlurMaskFilter.Blur style(模糊类型))
EmbossMaskFilter//浮雕效果
new EmbossMaskFilter(float[] direction(光源的方向),float ambient(环境光强度),float specular(炫光系数),float blurRadius(光线范围))
获取绘制的Path
getFillPath(Path src,Path dst)//实际path
getTextPath(Stirng text,int start,int end,float x,float y,Path)/getTextPath(char[] text,int index,int count,float x,float y,Path path)//文字的path
drawTextOnPath()//沿一条Path来绘制文字
StaticLayout //绘制文字,支持换行
paint.setFakeBoldText(booleab fakeBoldText)//是否使用伪粗体
paint.setStrikeThruText()//是否加删除线
paint.setUnderLineText(boolean underlineText)//是否加下划线
paint.setTextSkewX(float skewX)//设置文字横向错切角度
paint.setTextScaleX(float scaleX)//设置文字横向放缩
paint.setLetterSpacing(float letterSpacing)//设置字符间距,默认为0
paint.setTextAlign(Paint.Align align)//LEFT、CENTER、RIGHT默认为LEFT
paint.setTextLocale(Locale locale)/paint.setTextLocales(LocaleList locales) //设置绘制所用的地域
paint.setHinting(int mode)//是否启用字体微调
测量文字尺寸类:
paint.getFontSpacing();//获取推荐的行距
paint.getFontMetrics();//获取point的FontMetrics
baseline:基准线
ascent/descent:普通字符的顶部和底部范围
top/bottom:限制字型的顶部和底部
leading:行的额外间距,即上一行字的bottm与下一行字的top距离
paint.getTextBounds(String text(测量的文字),int start(文字的起始位置),int end(文字的结束位置),Rect bounds(文字显示范围的对象))//获取文字的显示范围
paint.measureText(String text)//测量文字占用的宽度
measureText()getTextBounds()
paint.getTextWidths(String text,float[] widths)//获取字符串中每个字符的宽度,并把结果填入参数widths
paint.breakText(String text((要测量的文字),boolean measureForwards(测量的方向),float maxWidth(宽度上限(超出上限会截断文字)),float[] measuredWidth(用于接受数据))//测量完成后会把文字宽度赋给measureWidth[0]
paint.getRunAdvance(CharSequence text,int start(文字的起始坐标),int end(文字的结束坐标),int contextStart(上下文的起始坐标),int ContextEnd(上下文的结束坐标),boolean isRtl(文字的方向),int offset(字数的偏移))//计算某个字符处光标的x坐标
paint.getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)//计算出文字中最接近这个位置的字符偏移量
paint.hasGlyph(String s)//检查指定的字符串是否是一个单独的字型
canvas.clipRect()//范围裁剪
canvas.clipPath()//根据范围裁剪
canvas.translate(float dx,float dy)//位移
canvas.rotate(float degrees,float px,float py)//旋转
canvas.scale(float sx(横向缩放倍数),float sy(纵向缩放倍数),float px,float py)//缩放
canvas.skew(float sx(x轴的错切系数),float sy(y轴的错切系数))//错切
canvas.setMatrix(matrix)//用Matrix直接替换Canvas当前的变换矩阵
canvas.concat(matrix)//用Canvas当前的变换矩阵和Matrix相乘
Camera.rotate*()//三维旋转
1、super.draw()//总调度方法
2、super.onDraw()
3、dispatchDraw()//绘制子View的方法
绘制顺序:
draw()总调度方法,view的绘制过程都发生在draw()方法里
1、背景(drawBackground()不能重写)-------android:background:/View.setBackgroundXxx()
2、主体(onDraw())
3、子View(dispatchDraw())
4、滑动边缘渐变和滑动条(onDrawForeground())-------android:scrollbarXxx/View.setXXXScrollBarXXX()
5、前景(onDrawForeground())-------android:foreground/View.setForeground()
view.animate().translationX()//x轴偏移
1、如果是自定义控件,需要添加setter、getter方法
2、ObjectAnimator.ofXXX()创建ObjectAnimator对象
3、用start()方法执行动画
setDuration(int duration)//设置动画时长
setInterpolator(Interpolator interpolator)//设置插值器
ViewPropertyAnimator.setListener()/ObjectAnimator.addListener()
ViewPropertyAnimator.setUpdateListener()/ObjectAnimator.addUpdateListener()
ObjectAnimator.addPauseListener()
ViewPropertyAnimator.withStartAction/EndAction()
ArgbEvaluator//颜色渐变动画
PropertyValuesHolder//同一个动画中改变多个属性
PropertyValuesHolders.ofKeyframe()//把同一个属性拆分
AnimatorSet//多个动画配合执行
targetSdkVersion=14,硬件加速默认开启
view.setLayerType()
LAYER_TYPE_SOFTWARE:使用软件来绘制View Layer,绘制到Bitmap,并顺便关闭硬件加速
LAYER_TYPE_HARDWARE:使用GPU来绘制View Layer,绘制到OpenGL texture(如果硬件加速关闭,那么行为和LAYER_TYPE_SOFTWARE一致)
LAYER_TYPE_NONE:关闭View Layer
View Layer可以加速无invalidate()(例如动画)时的刷新效率,但对于需要调用invalidate()的刷新无法加速
硬件加速并不支持所有的绘制操作
1、测量(measure)
View:View在onMeasuer中会计算自己的尺寸然后保存
ViewGroup:ViewGroup在onMeasure中会调用所有子View的measure让它们进行自我测量,并根据子View
计算出的期望尺寸来计算他们的事迹尺寸和位置然后保存。
2、布局(layout)
View:无子View所以onLayout不做任何处理
ViewGroup:ViewGroup在onLayout中会调用自己所有子View的layout方法,把他们的尺寸、位置传给他们, 让他们完成自我布局。
MeasureSpec = mode + size :父类传递过来给当前View的一个建议值
MeasureSpec.getMode(int spec)//获取模式
MeasureSpec.getSize(int spec)//获取数值
限制分类:
UNSPECIFIED(不限制)
AT_MOST(限制上限)-wrap_content
EXACTLY(限制固定值)-match_parent/具体值
1、重写onMeasure来修改已有的View尺寸
(1)、重写onMeasure方法,调用super.onMeasure触发原有的自我测量。
(2)、在super.onMeasure下用getMeasureWidth与getMeasureHeigh获取之前测量的结果,使用自己的算法计算新结果。
(3)、调用setMeasureDimension保存新结果。
2、重写onMeasure来全新定制自定义View的尺寸
与1区别,保证计算的同时,保证结果满足父View给出的尺寸限制
(1)重写onMeasure,计算出View的尺寸
(2)使用resolve让子View的计算结果符合父View的限制,也可不使用该方法自己定义
3、重写onMeasure和onLayout来全新定制自定义ViewGroup的内部布局
两个注意点:
子控件间的margin值
1、重写generateLayoutParams()和generateDefaultLayoutParams()
2、获取margin值 MarginLayoutParams lp = (MarginLayoutParams )child.getLayoutParams()
子控件间的padding值
1、测量后直接getPaddingLeft、getPaddingTop、getPaddingRight、getPaddingBottom
重写onMeasure来计算内部布局
(1)调用每个子View的measure来计算子View的尺寸
结合layout_xxx和自己可用空间
(2)计算子View的位置并保存子View的尺寸和位置
(3)计算自己的尺寸并用setMeasureDimension保存
重写onLayout来摆放子View
(1)调用每个子View的layout,让他们保存自己的位置和尺寸
view工作原理
触摸事件
1、ACTION_DOWN:手指刚接触屏幕,按下去的那一瞬间
2、ACTION_MOVE:手指在屏幕上移动
3、ACTION_UP:手指从屏幕上松开的瞬间
事件序列:从ACTION_DOWN - ACTION_UP
ViewGroup:
DispatchTouchEvent
• return true:表示该View内部消化掉了所有事件
• return false:表示事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费
• return super.dispatchTouchEvent(ev):默认事件将分发给本层的事件拦截onInterceptTouchEvent方法 进行处理
OnInterceptTouchEvent
• return true:表示将事件进行拦截,并将拦截到的事件交由本层控件的onTouchEvent进行处理
• return false:表示不对事件进行拦截,事件得以成功分发到子View
• return super.onInterceptTouchEvent(ev):默认表示不拦截该事件,并将事件传递给下一层View的 dispatchTouchEvent
OnTouchEvent 默认false
• return true:表示onTouchEvent处理完事件后消费了此次事件
• return fasle:表示不响应事件,那么该事件将会不断向上层View的onTouchEvent方法传递,直到某个View的 onTouchEvent方法返回true
• return super.dispatchTouchEvent(ev):表示不响应事件,结果与return false一样
子View不存在分发:
• DispatchTouchEvent 事件分发
• OnTouchEvent 默认true
如下图为事件分发流程图:
---------------------- 以上总结部分源自Hencoder教程 ------------------------------
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流