自定义View的一些疑点

一、measureChildWithMargins( )和measureChild( )有什么相同点和区别

  1. measureChildWithMargins( )和measureChild( )均用来测量子View的大小
  2. 两者在调用getChildMeasureSpec( )均要计算父View已占空间
  3. 在measureChild( )计算父View所占空间为mPaddingLeft + mPaddingRight,即父容器左右两侧的padding值之和
  4. measureChildWithMargins( )计算父View所占空间为mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin+ widthUsed。此处,除了父容器左右两侧的padding值之和还包括了子View左右的margin值之和( lp.leftMargin + lp.rightMargin),因为这两部分也是不能用来摆放子View的应算作父View已经占用的空间。这点从方法名measureChildWithMargins也可以看出来它是考虑了子View的margin所占空间的
二、measure和layout这两个过程的小结
1、 获取View的测量大小measuredWidth和measuredHeight的时机。 
在某些复杂或者极端的情况下系统会多次执行measure过程,所以在onMeasure()中去获取View的测量大小得到的是一个不准确的值。为了避免该情况,最好在onMeasure()的下一阶段即onLayout()中去获取。 
2、 getMeasuredWidth()和getWidth()的区别 
在绝大多数情况下这两者返回的值都是相同的,但是结果相同并不说明它们是同一个东西。 
首先,它们的获取时机是不同的。 
在measure()过程结束后就可以调用getMeasuredWidth()方法获取到View的测量大小,而getWidth()方法要在layout()过程结束后才能被调用从而获取View的实际大小。 
其次,它们返回值的计算方式不同。 
getMeasuredWidth()方法中的返回值是通过setMeasuredDimension()方法得到的,这点我们之前已经分析过,在此不再赘述;而getWidth()方法中的返回值是通过View的右坐标减去其左坐标(right-left)计算出来的。 
一般在自定义控件的时候getMeasuredWidth/getMeasuredHeight它的赋值在View的setMeasuredDimension中,所以有时可以在onMeasure方法中看到利用getMeasuredWidth/getMeasuredHeight初始化别的参数。而getWidth/getHeight一直在onLayout完成后才会被赋值。一般情况下,如果都完成了赋值,两者值是相同的
3、 刚才说到了关于View的坐标,在这就不得不提一下: 
view.getLeft(),view.getRight(),view.getBottom(),view.getTop(); 
这四个方法用于获取子View相对于父View的位置。 
但是请注意: 
getLeft( )表示子View的左边距离父View的左边的距离 
getRight( )表示子View的右边距离父View的左边的距离 
getTop( )表示子View的上边距离父View的上边的距离 
getBottom( )表示子View的下边距离父View的上边的距离 
在此,画一个示例图作为参考 
这里写图片描述 
4、 直接继承自ViewGroup可能带来的复杂处理。 
刚通过一个例子简单模拟了ViewGroup的onLayout()过程;其实,说简单已经算是含蓄的了;如果要粗暴地说那就是简单得令人发指。因为项目开发中实际的情况可能远比这个复杂;比如,在ViewGroup中包含了多个View,每个View都设置了padding和margin,除此之外还可能包含各种嵌套。在这种情况下,我们在onMeasure()和onLayout()中都要花费大量的精力来处理这些问题。所以在一般情况下,我们可以选择继承自LinearLayout,RelativeLayout等系统已有的布局从而简化这两部分的处理。

三、自定义View过程中要注意的

  1. 直接继承自View 
    在使用该方式实现自定义View时通常的核心操作都在onDraw( )当中进行。但是,请注意,在分析measure部分源码的时候,我们提到如果直接继承自View在onMeasure( )中要处理view大小为wrap_content的情况,否则这种情况下的大小和match_parent一样。除此以为,还需要注意对于padding的处理。

  2. 继承自系统已有的View 
    比如常见的TextView,Button等等。如果采用该方式,我们只需要在系统控件的基础上做出一些调整和扩展即可,而且也不需要去自己支持wrap_content和padding。

  3. 直接继承自ViewGroup 
    如果使用该方式实现自定义View,请注意两个问题 
    第一点: 
    在onMeasure( )实现wrap_content的支持。这点和直接继承自View是一样的。 
    第二点: 
    在onMeasure( )和onLayout中需要处理自身的padding以及子View的margin

  4. 继承自系统已有的ViewGroup 
    比如LinearLayout,RelativeLayout等等。如果采用该方式,那么在3中提到的两个问题就不用再过多考虑了,简便了许多。

四、View的Touch事件处理流程做一个总结

这里写图片描述

  1. View处理Touch事件的总体流程 
    dispatchTouchEvent()—>onTouch()—>onTouchEvent()—>onClick() 
    Touch事件最先传入dispatchTouchEvent()中;如果该View存在TouchListener那么会调用该监听器中的onTouch()。在此之后如果Touch事件未被消费,则会执行到View的onTouchEvent()方法,在该方法中处理ACTION_UP事件时若该View存在ClickListener则会调用该监听器中的onClick()
  2. onTouch()与onTouchEvent()以及click三者的区别和联系 
    2.1 onTouch()与onTouchEvent()都是处理触摸事件的API 
    2.2 onTouch()属于TouchListener接口中的方法,是View暴露给用户的接口便于处理触摸事件,而onTouchEvent()是Android系统自身对于Touch处理的实现 
    2.3 先调用onTouch()后调用onTouchEvent()。而且只有当onTouch()未消费Touch事件才有可能调用到onTouchEvent()。即onTouch()的优先级比onTouchEvent()的优先级更高。 
    2.4 在onTouchEvent()中处理ACTION_UP时会利用ClickListener执行Click事件。所以Touch的处理是优先于Click的 
    2.5 简单地说三者执行顺序为:onTouch()–>onTouchEvent()–>onClick()
  3. View没有事件的拦截(onInterceptTouchEvent( )),ViewGroup才有,请勿混淆 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值