自定义View之总结

自定义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程序员日记
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容