文章收藏的好句子:成功从来不是一蹴而就,而是日积月累的努力叠加的结果。

ps:本文是基于 Android API 31 来分析的,文章写的 demo 是用 AndroidStudio 工具来开发的。

目录

1、自定义 View 的分类

2、自定义 View 的注意事项

3、自定义 View 的实例

1、自定义 View 的分类

自定义 View 的分类到目前还没有统一的标准,以我对自定义 View 的学习积累,我把自定义 View 规划为以下这4类。

(1)直接继承于 View 

直接继承于 View 来绘制一些不规则的视图,需要通过绘制的方式来实现,也就是要重写 View 的 onDraw方法;直接继承于 View 的子类都是需要自己去处理 wrap_content (看Android中View的工作流程之measure过程这篇文章,如果自定义的 View 直接继承 View 不处理 wrap_content,那么就和 match_parent 的效果是一样的)和 padding ,否则做出来的效果和我们实现的不一样。

(2)直接继承于 ViewGroup

这种方法用于实现自定义的布局,像 LinearLayout、RelativeLayout 等是属于系统的布局,如果我们需要重新定义一种新布局,可以采用这种方法来实现,比如说布局可以左右(把ViewPager看作是一种自定义布局嘛)且还产生水波纹效果的时候,用这种方式有点复杂,需要适当地处理 ViewGroup 的测量、布局这两个过程,与此同时处理子元素的测量和布局过程。

(3)直接继承于具体的 View(例如 TextView)

用于拓展某种已具有的 View 功能,比如说 TextView,它被 Button 继承着,Button 主要用来设置点击事情的;直接继承于具体的 View,它不需要自己去处理 wrap_content 和 padding。

(4)直接继承于具体的 ViewGroup(例如 FrameLayout)

如果某种效果看起来和具体的 ViewGroup 很像的时候,也就是和具体的 ViewGroup 布局子元素特性很像的时候,可以采用这种方法来实现,采用这种方法不需要自己处理 ViewGroup的 measure 和 layout 这两个过程。

一种 View 的显示效果有很多种自定义 View 的方式去实现,喜欢用哪种最终还是看开发者自己的喜好,好,我们现在说一下自定义 View 应该注意的一些事项。

2、自定义 View 的注意事项

(1)直接继承于 View 或者 ViewGroup,当用到 wrap_content 值时,必须支持 wrap_content;如果不在 onMeasure 中对 wrap_content 做特殊处理,那么当自定义 View 或者自定义 ViewGroup 在布局中使用 wrap_content 时就没法达到预期的效果,那么我们看到的就是和 match_parent 一样的效果,可以看Android中View的工作流程之measure过程这篇文章,你们就可以看到和 match_parent 一样的效果了。

(2)如果直接继承 View 且使用到 padding 时,如果不在 draw 方法中处理 padding,那么 padding 属性就不会起作用;如果直接继承自 ViewGroup 并且使用到 wrap_content 时,需要在 onMeasure 和 onLayout 方法中处理 padding 和子 View 的 margin 对它造成的影响。

(3)不要在自定义 View 中创建一个 Handler ,因为 View 提供了 post 一系列的方法,View 的一系列 post 方法其实还是调用了 Handler 的 post 一系列的方法。

(4)当 View 变得不可见时我们需要停止线程和动画,如果不处理这种情况,很容易造成内存泄漏;如果有线程或者动画需要停止时,最好是在 View 的 onDetachedFromWindow 方法中进行调用,因为 Activity 退出或者 View 被删除的时候,View 的 onDetachedFromWindow 方法会被执行。

(5)如果 View 存在滑动冲突,应当处理好滑动冲突,否则会影响用户体验效果;有关滑动冲突的内容可以看Android中View的滑动冲突这篇文章。

3、自定义 View 的实例

我们这里就写一个直接继续于 View 的案例,我们就画一个椭圆,步骤如下所示;

(1)写一个 EllipseView并继承于 View;

package com.xe.myapplication4;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;/*** Created by 86188 on 2022/7/7.*/public class EllipseView extends View {Paint p;private int color;public EllipseView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(context,attrs);}public EllipseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context,attrs);}private void init(Context context, @Nullable AttributeSet attrs) {p = new Paint();TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.EllipseView);//1、color = ta.getColor(R.styleable.EllipseView_ellipse_view_color,Color.GREEN);ta.recycle();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);//2、if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {setMeasuredDimension(200,150);//3、} else if (widthSpecMode == MeasureSpec.AT_MOST) {setMeasuredDimension(200,heightSpecSize);//4、} else if (heightSpecMode == MeasureSpec.AT_MOST) {setMeasuredDimension(widthSpecSize,150);}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//5、int leftPadding = getPaddingLeft();int rightPadding = getPaddingRight();int topPadding = getPaddingTop();int buttomPadding = getPaddingBottom();int width = getMeasuredWidth();int height = getMeasuredHeight();int width2 = width  - rightPadding;int height2 = height  - buttomPadding;p.setColor(color);p.setAntiAlias(true);RectF rectF = new RectF();rectF.set(leftPadding,topPadding,width2,height2);canvas.drawOval(rectF, p);}
}

(2)在 values 目录下创建一个 attrs.xml 文件,并自定义一个 ellipse_view_color属性,格式为 color 类型的,其值就是颜色值;

(3)自定义 View 在 xml 中的布局;

说明:

1)看注释1,它是解析自定义属性的 ellipse_view_color 值,如果在 xml 布局文件中没有使用该属性,那么就默认为绿色。

2)看注释2、3、4,处理 wrap_content 模式,当宽在 wrap_content 模式时,就将宽设置为200;当高在 wrap_content模式时,就将高设置为150。

3)看注释5,获取上下左右的 padding,绘制自定义 View 时处理 padding。

4)看注释6的 ellipse_view_color 属性,是不是有 app 的前缀?这是自定义属性的标志,使用自定义属性时必须在 xml 布局文件中添加 schemas 声明:xmlns:app="http://schemas.android.com/apk/res-auto"。

程序运行结果如下所示;

Android中的自定义View(一)相关推荐

  1. Android中的自定义View以及绘图工具

    1.1自定义view的简介 为什么要使用自定义view 在Android开发中有很多业务场景,原生的控件是无法满足应用,并且经常也会遇到一个UI在多处 重复使用情况,那么就需要通过自定义View的方式 ...

  2. Android中的自定义view和自定义属性TypedArray的使用

    先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 [ 3.重写onMesure ] 4.重写onDraw 我把3用[]标出了,所以说3不一定是必 ...

  3. Android中实现自定义View组件并使其能跟随鼠标移动

    场景 实现效果如下 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建An ...

  4. android中使用自定义View让图片像画卷一样被展开显示

    首先看下效果图,有点卡顿,这是因为我是用android studio的screen record来录制手机视频的,然后找不到合适的mp4->gif的软件,就使用了一个录屏的软件,所以有点卡顿,但 ...

  5. Android中自定义View的研究 -- 在XML中引用自定义View

    如果在一直使用SetContentView(new HellwView(this)觉得总是少了一点东西,少了什么了,失去了Android中使用XML定义组件的便携性,这种感觉让人很不爽,呵呵,在这节里 ...

  6. android 在xml文件中引用自定义View

    在xml中引用自定义view 方法一: [java] view plaincopy <com.test.copytext.CopyText android:layout_width=" ...

  7. android 自定义view xml ,Android实现在xml文件中引用自定义View的方法分析

    本文实例讲述了Android实现在xml文件中引用自定义View的方法.分享给大家供大家参考,具体如下: 在xml中引用自定义view 方法一: android:layout_width=" ...

  8. 如何在android中创建自定义对话框?

    本文翻译自:How to create a Custom Dialog box in android? I want to create a custom dialog box like below ...

  9. android标尺自定义view,android尺子的自定义view——RulerView详解

    项目中用到自定义尺子的样式: 原效果为 因为跟自己要使用的view稍有不同 所以做了一些修改,修改的注释都放在代码中了,特此记录一下. 首先是一个自定义View: public class RuleV ...

最新文章

  1. 真我新格调 勇敢使梦想×××
  2. python开发环境配置以及其简单的运行方式
  3. C#下实现的基础K-MEANS多维聚类
  4. 获取前一天的时间安排表_【央美考研】2021年硕士研究生招生入学考试时间安排...
  5. Xcode7 无账号真机测试!!
  6. 深度学习中的“卷积”与数学中的“卷积”有何不同
  7. 手把手教你用R语言制作网络爬虫机器人(一)
  8. 请在微信客户端打开链接
  9. APP在推广之渠道为王(三 )
  10. 交换机与路由器的配置
  11. OSChina 周五乱弹 ——程序员看火影忍者被女同事鄙视了
  12. kafka的Leader选举机制
  13. php做excel导入word,php如何将excel表格插入到word文档
  14. 【HTML系列】第二章 · HTML基础
  15. Linux---C语言连接数据库(1)
  16. 书法拓片matlab,书法拓片是怎么做出来的?
  17. 双足机器人的稳定性判据_双足机器人行走稳定性探究.pdf
  18. 怎么批量对多个视频文件进行消音处理
  19. 标准cpci接口定义_CPCI数据总线接口的设计与实现
  20. Altium Designer,PCB处理最后GND以及铺铜经验

热门文章

  1. Matlab 颜色、线型、标记符号和希腊字母表
  2. 系统中的DTO与MO
  3. C++四种cast的详细介绍
  4. matlab中矩阵的表示与简单操作
  5. 修改ftp服务器地址,ftp服务器的地址修改
  6. 系统克隆 机械硬盘无缝迁移到ssd
  7. linux内核源码—编程之路
  8. H3C服务器修改启动项,H3C服务器 iFIST快速安装指南-6W102
  9. 方形图片使用QLabel显示成圆形
  10. Java语言简介和基础