自定义View之总结

作者: 贤榆的榆 | 来源:发表于2016-07-16 23:48 被阅读3389次
    自定义View之总结

    文章来自:Android程序员日记

    作者:贤榆的鱼

    参考阅读时间:5 min 15s

    导读语:自定义控件只看这一篇,是不够的!

    前言

    在之前我先后写了"自定义View之扩展式"、"自定义View之复合式"、"自定义View之完全自定义",在这三篇文章中我都分别给出了一个例子。当然了,例子其实是相对比较简单的,主要原因可能是个人水平有限吧!但尽管如此,我也尽可能把我要讲的内容表述的更清晰一些!那么为了更好的在我们的脑海里构建这个知识框架(这句话太专业,让我写起来都感到了满满的压力!其实就是让某些重要的或是会用到的内容,能够在我们大脑里留下个更深刻的印象,并让他们之间有更多的联系。)以便于在我们需要的时候,更容易提取出来用!为此,写个总结也是一个不错的方法!这个观点是来自《暗时间》!

    正文

    我们暂且将自定义View分为了扩展式、复合式和完全自定义三种类型(当然我们也可以按别的分)!他们看起来确实有一定的从易到难的梯度关系!不管怎样,我们将这前面三遍中的知识点和自定义View的一些知识点做一个总结!好处就是——可能会有跟多人关注我的“Android程序员日记”的公众号吧!

    都说程序员都是从零开始计数的,那我们开始吧!

    [ 0 ]关于自定义View的三个构造方法

    • 一个参数的构造方法:在用代码动态的添加我们的自定义view时调用。
    • 两个参数的构造方法:在使用xml +inflate的方法添加控件时会调用,里面多了一个AttributeSet类型的值
    • 三个参数的构造方法:这个构造方法系统是不调用的,需要我们显示调用并给defStyleAttr传值,多了一个defStyleAttr参数,这是这个view引用style资源的属性参数,也就是我们可以在style中为自定义View定义一个默认的属性样式然后添加进来!

    [ 1 ]关于三种自定义View

    • 扩展式:

      扩展式自定义View继承自Android原生特定的View如:TextView,ImageView等等。我们通过重写onDrow()等回调方法对其进行扩展!使其实现我们想要的更能或样式!

      注:该方法实现的自定义View控件不需要自己支持wrap_content和padding。

    • 组合式:

      组合式自定义View继承自ViewGrop的子View如:LinearLayout、RelativieLayout等。当某种效果看起来像几种View组合在一起的时候,都可以使用这种方式实现。

      注:该方式实现自定义View不需要自己处理ViewGroup的测量和布局这两个过程。

    • 完全自定义:
      完全自定义View继承自View(android中所有控件的基类),通常实现一些不方便布局的组合方式来达到的,需要静态或动态地显示一些不规则的控件或图形!

      注:该方法实现的自定义View控件需要自己支持wrap_content和padding。

    [ 2 ]常用的回调方法

    • onFinishInflate():加载完XML组件后回调
    • onSizeChanged():组件大小改变时回调
    • onMeasure():回调该方法来进行测量(在该方法中实现对wrap_content支持的代码)
    • onLayout():回调该方法来显示位置
    • onTouchEvent():监听到触摸事件回调,也是实现交互非常重要的回调方法
    • onDraw():回调该方法对我们的控件进行绘制

    [ 3 ]为自定义View添加并使用自定义属性的过程

    Step 1 : 在Values下创建attrs.xml(当然也可以以别的名字命名,无限制),然后在该文件中添加自定义View的自定义属性!

    Step 2 : 在自定义View的构造方法中获取自定义属性值,并将值配予相应的位置!

    Step 3 :在xml中使用自定义控件及配置其自定义属性

    注:在xml使用自定义控件时一定要加 :

    xmlns:custom="http://schemas.android.com/apk/res-auto"

    当然你也可以写成

    xmlns:custom="http://schemas.android.com/apk/res/com.timen4.t3"(com.timen4.t3是应用的报名)

    这两种方式没有本质上的区别。至于custom随便你喜欢命名什么都可以。

    [ 4 ]完全自定义控件中我们自己支持wrap_content和padding的代码

    • MeasureSpec
      • 简介:MeasureSpec代表一个32位int值,高2位代表SpecMode(测量模式),低30位代表SpecSize(指定模式下的规格大小)。

      • 三种SpecMode与SpecSize

        1.UNSPECIFIED:父容器自容器无限制,要多大给多大,这种情况一般用于系统内部。一般我们不关注盖模式。

        2.EXACTLY:父容器已检测出了View所需要的精确大小,这时V接我的最终大小就是SpecSize所给定的值。它对应于LayoutParams中的match_parent和具体的数值两种模式

        3.AT_MOST:父容器制定了一个可用大小即SpecSize,View的大小不能大于这个值,具体值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。

      • MeasureSpec和LayoutParams的对应关系
        普通的View(即非顶层View)的MeasureSpec由父容器的MeasureSpec和自身的LyoutParams来共同决定的,MeasureSpec一旦确定后,onMeasure中就可以确定View的测量宽高。但对于顶层View(即)

    • 对wrap_content的支持

      在onMeasure()方法中实现对wrap_content的支持

        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSpecSize= MeasureSpec.getSize(widthMeasureSpec);
            int heightSpectMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);
            //这里就是对wrap_content的支持
            if(widthSpecMode==MeasureSpec.AT_MOST&&heightSpectMode==MeasureSpec.AT_MOST){
                //这里设定的根据你自己自定义View的情况而定
                setMeasuredDimension(200,200);
            }else if(widthSpecMode==MeasureSpec.AT_MOST){
                setMeasuredDimension(200,heightSpecSize);
            }else if (heightSpectMode==MeasureSpec.AT_MOST){
                setMeasuredDimension(widthSpecSize,200);
            }
        }
      
    • 对padding的支持

      在onDraw()方法中实现对padding的支持,其实就是在或控件时考虑到就padding就好了。如果不自己实现那么你对该自定义View设置padding将是无效的!
      
        @Override
           protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //这里是对画一个圆形的View的padding支持
            final int paddingLeft = getPaddingLeft();
            final int paddingRight = getPaddingRight();
            final int paddingTop = getPaddingTop();
            final int paddingBottom=getPaddingBottom();
            int width = getWidth()-paddingLeft-paddingRight;
            int height = getHeight()-paddingBottom-paddingTop;
            int radius = Math.min(width,height)/2;
            canvas.drawCircle(paddingLeft+width/2,paddingTop+height/2,radius,mPaint_while);
        }
      

    [ 5 ]为自定义View定义并实现接口回调的过程

    本段示例代码来自"自定义View之复合式",为了总结的需要,做了一些注释上的修改,并简化为实现一个回调方法!

    Step 1: 定义回调接口(自定义View类中操作)

    public interface TopBarClickListener {
        void leftClick();
    }
    

    Step 2: 暴露回调接口(自定义View类中操作)

    public void setOnTopbarClickListener(TopBarClickListener mListener){
        this.mListener=mListener;
    }
    

    Step 3: 调用回调接口(自定义View类中操作)

    private void bindEvents() {
        mLeftButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mListener!=null){
                    mListener.leftClick();
                }
            }
        });
    }
    

    Step 4: 实现回调回调接口及方法(在实例化自定义View对象的类中)

    mtopBar.setOnTopbarClickListener(new TopBar.TopBarClickListener() {
        @Override
        public void leftClick() {
            Toast.makeText(MainActivity.this,"上一张",Toast.LENGTH_SHORT).show();
            if (index<=0){
                index=3;
            }else{
                index--;
            }
            iv_image.setImageResource(images.get(index));
        }
    

    后记

    好了,这篇总结就这么多了!我必须再次强调一次,本文最最重要的一句话,就是放在最前面的导读语——自定义控件只看这一篇,是不够的!这句话我没开玩笑,你不信也没关系,反正我是不会在哪我的美貌做赌注了!

    其实,不只是我对自己写的东西不自信,而是无论是我这一篇,还是某个大牛写的某一篇。我都觉得自定义View看某一篇是不够的!对于初学者或新手而言更是如此。因为正如我在我在前言中写道的一样,我们都在构造自己的知识架构。我们需要从更多的角度,去理解我们学到的或是要学习的内容!这样才更有助于我们去理解和记忆!也才更有助于我们去实际应用!

    最后总结一句话吧——“我们学习的任何事物”看“某一篇”都是不够的!


    喜欢可以关注我微信公众号
    分享绝不止于Android!


    喜欢请关注公众Android程序员日记

    相关文章

      网友评论

      • 93bd00a71476:一篇不够的观点,我有一种类似的感觉,看文章刚开始都是晦涩难懂,看多就觉得讲的通俗易懂,其实是多看几遍之后知识体系的建立。
        贤榆的榆: @yuanjunli 嗯😜
      • D13954:3个mode的解析,又让我了解了一些,然后组织语言描述又更好理解了一些。的确,我看了好几篇这样的文章了。我觉得继续看下其他人的,可能会找到自己需要的知识,然后记住,构建自己的那个xx。哈哈
        D13954:@贤榆的鱼 😂😂
        贤榆的榆: @小木邪 一路顺风😀
      • longsh: :tada:
        贤榆的榆:@86dc44fb59b4 谢谢你的关注
      • Benhero:很精练
        Benhero:@贤榆的鱼 再补充呗,哈哈,届时@下我哈,谢谢
        贤榆的榆: @奔ben苯笨 发了就觉得,还有部分没总结到。
      • f9895fb9acee:支持一个,,,
        贤榆的榆: @f9895fb9acee 谢谢,喜欢可以关注我的公众号😊
      • TheLights:学习😊

      本文标题:自定义View之总结

      本文链接:https://www.haomeiwen.com/subject/kuvujttx.html