常用的四种标准自定义View方法

转载于 http://blog.csdn.net/makeyourchance/article/details/51884861

(二)继承ViewGroup派生特殊的Layout 
这是真真实实的造”轮子“呀!需要你自己写view的OnMeasure()跟OnLayout()过程的逻辑,如果想写一个listView+Scrollview的变异Layout,那你还要处理滑动冲突的问题,我原来一直不明白,为什么我一定要懂事件分发机制(内部是一个树形结构),它有什么用?我现在知道了,那就是几乎所有的自定义相关的View或ViewGroup它在写处理的逻辑的时候的基础就是事件分发,比如:自定义Draw(),它内部有一个dispatchDraw()方法,一看名字是不是非常熟悉,哈哈~没错,跟Event的分发很类似,然后,我又想到——-为什么我要学习《离散数学》了?如果当时老师告诉我学它是干嘛用的,我一定好好学习,学渣表示已经还给老师了~好了,我们废话不多说,走起! 
我们先来看自定义ViewGroup的OnMeasure()方法(为什么先从它开始,因为这个渣渣很容易出错,而且很关键); 
思路: 
以前我们自定义View的时候,我只需要考虑它自己的测量就可以了,现在ViewGroup中放了很多个View ,你说怎么测量?当然是把它(即遍历)出来,然后测出宽高,然后求和,就是我要画的总宽高了呀!当然,这里有个假设必须成立—–那就是子View的宽高均相等;结合具体情况具体使用呀~比如:我要定义一个类似水平的LinearLayout ,这时候我的高就等于第一个子View的高,而宽则等于所以子View的总和,why ?因为你看手机图片的时候是不是左右滑动,而不是上下滑动,对否~上代码:

  创建CoustomViewGroup.java  
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * view测量原理:
     *      主要是MeasureSpace代表一个int 32位的值,高俩位分别为spaceMode(即测量模式),spaceSize(即测量大小)
     *      那3中测试模式这里就赘述了,自己搜一下,主要针对说下宽高属性为wrap_content的情况,加入任一属性为wrap_content时,
     *      高(宽)需要在onMeasure()方法中做特殊处理,不复杂,就是给一个默认值比如:200dp ,我在网上看到很多人都喜欢使用这个数字,
     *      不知道为什么?若二者都为wrap_content ,简单那就在OnMeasure()中都做处理给个默认值呗,就这么简单!
     *
     */</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onMeasure</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> widthMeasureSpec, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> heightMeasureSpec) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec);

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//定义俩个保存子Viw的测量宽跟高的变量measureWidth和measureHeight</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> measureChildWidth = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> measureChildheight = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//获取子view的个数</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> childCount = getChildCount();
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//测量ziView的宽高;</span>
        measure(widthMeasureSpec , heightMeasureSpec);


        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//下来就是套路了,确定测量的模式跟大小</span>

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> widSpaceSize = MeasureSpec.getSize(widthMeasureSpec);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//下来就是写自己的逻辑判断了,这里必须感谢下大牛----coder任玉刚 ,解决了我许久的困惑,</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 比如:为什么自定义view时宽高设置为warp_content时,不重写OnMeasure()方法,View的效果等同于math_parent?</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//先来判断下有没有子元素,没有就不用测了直接置0</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (childCount == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>){
            setMeasuredDimension(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
        }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ( (widthSpaceMode == MeasureSpec.AT_MOST) && (heightSpaceMode == MeasureSpec.AT_MOST) ){

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//还记得我们自定义View的时候的处理规范吗------setMeasuredDimension(200 , 200);</span>

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//获取第一个子View的对象</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> View childView = getChildAt(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
            measureChildWidth = childView.getMeasuredWidth() * childCount;
            measureChildheight = childView.getMeasuredHeight() * childCount;
            setMeasuredDimension(measureChildWidth , measureChildheight);

        }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ( widthSpaceMode == MeasureSpec.AT_MOST ){

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//当宽属性为wrap_content时,需要所有子View的宽之和(记得我们是水平的呀)</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> View childView = getChildAt(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
            measureChildWidth = childView.getMeasuredWidth() * childCount;
            setMeasuredDimension(measureChildWidth , heightSpaceSize);

        }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ( heightMeasureSpec == MeasureSpec.AT_MOST ){

            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//注意:当高属性为wrap_content时,仅仅需要任一子View的高即可(记得我们是左右滑动的,高是不变得)</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> View childView = getChildAt(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);
            measureChildheight = childView.getMeasuredHeight() ;
            setMeasuredDimension(widSpaceSize , measureChildheight);
        }
    }
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li></ul>

代码中的注释已经很完整了,这里就不在解释代码了~~我们继续,

NPC “任教主”的温馨提示: 
上面的OnMeasure()方法有俩点不规范:

NO .1 当没有子元素的时候,不应该直接把宽高置为0 ,而应该根据LayoutParams中的宽高来做相应的处理; 
No.2 在测量CoustomViewGroup的时候没有考虑它的padding 跟子View的margin会影响到CoustomViewGroup的宽高,why ?因为不管是自己的padding或者是子View的margin占用的都是CoustomViewGroup的空间;

小伙伴们,可以自己实现下,我们主要学习流程就不走细节了,咱们继续,来看看自定义ViewGroup的OnLayout()的过程,走起!

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
     * onLayout()过程主要用于确定view在ViewGroup中的摆放位置,通过确定View的L , T,R ,B四个坐标点;
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> b
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> i
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> i1
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> i2
     *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> i3
     */</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onLayout</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> b, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i1, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i2, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i3) {

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> childLeft = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> childCount = getChildCount();
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//mChildrenSize = childCount;// 这里没搞懂为什么要把childCount赋值给mChildrenSize ?</span>

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//接下来就是你熟悉的套路了,遍历每个子View并获取它们的位置, 从左向右</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> ( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> n = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> ; n < childCount ; n++){
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span>  View childView = getChildAt(n);
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//View可见</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ( (childView.getVisibility()) != View.GONE){
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> childWidth = childView.getMeasuredWidth();
                    mChildWidth = childWidth;
                    childView.layout(childLeft , <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> , childLeft + childWidth , childView.getMeasuredHeight());
                    childLeft += childWidth;
            }
        }
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>

同样任教主温馨提示时间到:

No.2 在测量CoustomViewGroup的时候没有考虑它的padding 跟子View的margin会影响到CoustomViewGroup的宽高,why ?因为不管是自己的padding或者是子View的margin占用的都是CoustomViewGroup的空间;

至于怎么处理让它变得规范,即具有处理padding及margin 的能力,就看法宝 吧~下面咱们继续分析:

我们都知道有View的监听方法有一个叫OnTechEvent()的,它里面有3个Action 分别为Action_Down , Action_Move ,ACtion_Up ,那么,我们从左向右滑动图片的时候,必然会涉及到这3个“怪”,我们要做的就是加入自己的逻辑判断规则,来劝化他们,怎么劝化呢?

我们可以这样: 
1)手指落下后会触发—-Down , 滑动会触发—-Move ,手指收起会触发—-Up ; 
2) 1怪跟3怪不足为虑,主要是2怪,它会产生一个滑动事件,我想让它把这个事件交给onTechEvent()的来处理,好那就重写onTechEvent()然而并没有什么卵用,这就涉及到一个事件分发的问题,至于事件分发的机制,网上多如牛毛,自己搜下吧~我们切入正题,事件分发机制遵循—–谁拦截谁负责到底的原则,当然,前提是onTechEvent()返回True (表示这个事件我来处理了) ,onInterceptTouchEvent()返回Treue(表示事件被截断,不在传递); 那么方法就是重写ViewGroup的onInterceptTouchEvent()方法,加入自己的逻辑判断;

好了,咱们明天继续~~你可以试着来实现一下!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值