首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Android 自定义控件 自定义 View 入门必备

Android 自定义控件 自定义 View 入门必备

作者头像
圆号本昊
发布2021-09-24 11:30:28
发布2021-09-24 11:30:28
9390
举报
文章被收录于专栏:github@hornhuanggithub@hornhuang

自定义 View

在实际使用的过程中,我们经常会接到这样一些需求,比如环形计步器,柱状图表,圆形头像等等,这时我们通常的思路是去Google 一下,看看 github 上是否有我们需要的这些控件,但是如果网上收不到这样的控件呢?这时我们经常需要自定义 View 来满足需求。


接下来让我们开启自定义控件之路

关于自定义控件,一般辉遵循一下几个套路

  1. 首先重写 onMeasure() 方法
  2. 其次重写 onDraw() 方法

总所周知 onMeasure() 方法是用来重新测量,并设定控件的大小,我们知道控件的大小是用 width 和 height 两个标签来设定的。通常有三种赋值情况 :

  1. 首先直接赋值,比如直接给定 15dp 这样确切的大小
  2. 其次 match_parent
  3. 当然还有 wrap_parent

这时也许你就会有疑问,既然都已经有了这些属性,那还重写 onMeasure 干嘛,直接调用 View 的方法不就行了吗?但是你想想,比如你设计了一个圆形控件,用户在 width 和 height 都设置了 wrap_parent 属性,同时又给你传了一张长方形的图片,那结果会怎么样?必然得让你“方”啊。。所以这时就需要重写 onMeasure 方法,设定其宽高相等。


那么该如何重写 onMeasure() 方法呢?

首先把 onMeasure() 打出来

代码语言:javascript
复制
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

这时大家不眠会好奇,明明是重绘大小,那么给我提供宽高就行了呀?这个 int widthMeasureSpec, int heightMeasureSpec ,是个什么鬼?其实很好理解,大家都知道计算机中数据是已二进制存储的。同时,就像我之前讲的 View 的大小赋值形式有三种,那么在计算机中,要存储二进制数,需要几位二进制呢,答案很明了 -> 两位。同时大家也发现,这两个参数都是 int 型的。int 型数据在计算机中用 30为存储。所以聪明的 Google 就把这 30 位划分为两部分。第一部分两位拿来存类型,后面 28 位拿来存数据大小。


开始重写 onMeasure() 方法

首先,无论是 width 还是 height ,我们都得先判断类型,再去计算大小,so~ 咱先写个方法专门用于计算并返回大小。

测量模式

表示意思

UNSPECIFIED

父容器没有对当前View有任何限制,当前View可以任意取尺寸

EXACTLY

当前的尺寸就是当前View应该取的尺寸

AT_MOST

当前尺寸是当前View能取的最大尺寸

代码语言:javascript
复制
   private int getMySize(int defaultSize, int measureSpec) {
        // 设定一个默认大小 defaultSize
        int mySize = defaultSize;
        // 获得类型
        int mode = MeasureSpec.getMode(measureSpec);
        // 获得大小
        int size = MeasureSpec.getSize(measureSpec);
        
        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
                mySize = defaultSize;
                break;
            }
            case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
                //我们将大小取最大值,你也可以取其他值
                mySize = size;
                break;
            }
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
                mySize = size;
                break;
            }
        }
        return mySize;
    }

然后,我们再从 onMeasure() 中调用它

代码语言:javascript
复制
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 分别获得长宽大小
        int width = getMySize(100, widthMeasureSpec);
        int height = getMySize(100, heightMeasureSpec);

        // 这里我已圆形控件举例
        // 所以设定长宽相等
        if (width < height) {
            height = width;
        } else {
            width = height;
        }
        // 设置大小
        setMeasuredDimension(width, height);
    }

在 xml 中应用试试效果

代码语言:javascript
复制

到这里图就已经重绘出来了,让我们运行一下下

我们惊呆了,说好的控件呢??! 别急,咱还没给他上色呢,所以它自然是透明的。所以现在重写 onDraw() 方法,在 onDraw() 方法中 

我们通过 canvas (安卓的一个绘图类对象进行图形的绘制)

代码语言:javascript
复制
    @Override
    protected void onDraw(Canvas canvas) {
        // 调用父View的onDraw函数,因为View这个类帮我们实现了一些
        // 基本的而绘制功能,比如绘制背景颜色、背景图片等
        super.onDraw(canvas);
        int r = getMeasuredWidth() / 2;//也可以是getMeasuredHeight()/2,本例中我们已经将宽高设置相等了
        Log.d(TAG, r + "");
        // 圆心的横坐标为当前的View的左边起始位置+半径
        int centerX = r;
        // 圆心的纵坐标为当前的View的顶部起始位置+半径
        int centerY = r;
        // 定义灰色画笔,绘制圆形
        Paint bacPaint = new Paint();
        bacPaint.setColor(Color.GRAY);
        canvas.drawCircle(centerX, centerY, r, bacPaint);
        // 定义蓝色画笔,绘制文字
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setTextSize(60);
        canvas.drawText("大傻瓜", 0, r+paint.getTextSize()/2, paint);
    }

运行一下


到此为止基本的自定义 View 就搞定了,下一篇我们来讨论下 怎么在 xml 中自定义参数

点击查看 https://blog.csdn.net/qq_43377749/article/details/91049344

关于本片博文中的代码我一进保存到

点击查看 https://github.com/FishInWater-1999/android_view_user_defined_first

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/06/06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义 View
  • 接下来让我们开启自定义控件之路
  • 那么该如何重写 onMeasure() 方法呢?
  • 开始重写 onMeasure() 方法
  • 运行一下
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档