一、自定义View的分类

自定义View一共分为两大类,具体如下图:

二、具体介绍 & 使用场景

对于自定义View的类型介绍及使用场景如下图:

三、使用注意点

在使用自定义View时有很多注意点(坑),希望大家要非常留意:

1.支持特殊属性
  • 支持wrap_content

如果不在onMeasure()中对wrap_content作特殊处理,那么wrap_content属性将失效
支持padding & margin

  • 如果不支持,那么padding和margin(ViewGroup情况)的属性将失效

对于继承View的控件,padding是在draw()中处理
对于继承ViewGroup的控件,padding和margin会直接影响measure和layout过程

2.多线程应直接使用post方式

View的内部本身提供了post系列的方法,完全可以替代Handler的作用,使用起来更加方便、直接。

3.避免内存泄露

主要针对View中含有线程或动画的情况:当View退出或不可见时,记得及时停止该View包含的线程和动画,否则会造成内存泄露问题。

启动或停止线程/ 动画的方式:
启动线程/ 动画:使用view.onAttachedToWindow(),因为该方法调用的时机是当包含View的Activity启动的时刻
停止线程/ 动画:使用view.onDetachedFromWindow(),因为该方法调用的时机是当包含View的Activity退出或当前View被remove的时刻

4. 处理好滑动冲突

当View带有滑动嵌套情况时,必须要处理好滑动冲突,否则会严重影响View的显示效果。

四、示例

  • 如何实现一个基本的自定义View(继承VIew)
  • 如何自身支持padding属性
  • 如何为自定义View提供自定义属性(如颜色等等)
1.创建自定义View类(继承View类)
/*** CircleView.java* 作用:绘制自定义View的具体内容* 需复写方法:onDraw()* 复写逻辑:具体绘制逻辑*/ public class CircleView extends View {// 设置画笔变量Paint mPaint1;// 自定义View有四个构造函数// 如果View是在Java代码里面new的,则调用第一个构造函数public CircleView(Context context){super(context);// 在构造函数里初始化画笔的操作init();}// 如果View是在.xml里声明的,则调用第二个构造函数// 自定义属性是从AttributeSet参数传进来的public CircleView(Context context,AttributeSet attrs){super(context, attrs);init();}// 不会自动调用// 一般是在第二个构造函数里主动调用// 如View有style属性时public CircleView(Context context,AttributeSet attrs,int defStyleAttr ){super(context, attrs,defStyleAttr);init();}// API21之后才使用// 不会自动调用// 一般是在第二个构造函数里主动调用// 如View有style属性时public  CircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}// 画笔初始化private void init() {// 创建画笔mPaint1 = new Paint ();// 设置画笔颜色为蓝色mPaint1.setColor(Color.BLUE);// 设置画笔宽度为10pxmPaint1.setStrokeWidth(5f);//设置画笔模式为填充mPaint1.setStyle(Paint.Style.FILL);}// 关键点:复写onDraw()进行绘制  @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 获取控件的高度和宽度int width = getWidth();int height = getHeight();// 设置圆的半径 = 宽,高最小值的2分之1int r = Math.min(width, height)/2;// 画出圆(蓝色)// 圆心 = 控件的中央,半径 = 宽,高最小值的2分之1canvas.drawCircle(width/2,height/2,r,mPaint1);}}

在布局文件中添加自定义View类的组件及显示:

/*** 1. 在布局文件中添加自定义View类的组件* activity_main.xml*/ <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="scut.carson_ho.diy_view.MainActivity"><!-- 注意添加自定义View组件的标签名:包名 + 自定义View类名--><!--  控件背景设置为黑色--><scut.carson_ho.diy_view.CircleViewandroid:layout_width="match_parent"android:layout_height="150dp"android:background="#000000"
</RelativeLayout>/*** 2. 设置显示* MainActivity.java*/ public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}

至此,一个基本的自定义View已经实现了,运行效果如下图

2.手动支持wrap_content属性


如果不手动设置支持padding属性,那么padding属性在自定义View中是不会生效的。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="scut.carson_ho.diy_view.MainActivity"><scut.carson_ho.diy_view.CircleViewandroid:layout_width="match_parent"android:layout_height="match_parent"/**  添加Padding属性,但不会生效 **/android:padding="20dp"/>
</RelativeLayout>

在自定义View类的复写onDraw()进行设置

/*** 复写的onDraw()*/ @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 获取传入的padding值final int paddingLeft = getPaddingLeft();final int paddingRight = getPaddingRight();final int paddingTop = getPaddingTop();final int paddingBottom = getPaddingBottom();// 获取绘制内容的高度和宽度(考虑了四个方向的padding值)int width = getWidth() - paddingLeft - paddingRight ;int height = getHeight() - paddingTop - paddingBottom ;// 设置圆的半径 = 宽,高最小值的2分之1int r = Math.min(width, height)/2;// 画出圆(蓝色)// 圆心 = 控件的中央,半径 = 宽,高最小值的2分之1canvas.drawCircle(paddingLeft+width/2,paddingTop+height/2,r,mPaint1);}


提供自定义属性
除了常见的以android:开头的系统属性(如下所示),很多场景下自定义View还需要系统所没有的属性,即自定义属性。

// 基本是以android开头
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:padding="30dp"
3.提供自定义属性

在values目录下创建自定义属性的xml文件

/*** attrs_circle_view.xml*/ <?xml version="1.0" encoding="utf-8"?><resources>// 自定义属性集合:CircleView// 在该集合下,设置不同的自定义属性<declare-styleable name="CircleView">// 在attr标签下设置需要的自定义属性// 此处定义了一个设置图形的颜色:circle_color属性,格式是color,代表颜色// 格式有很多种,如资源id(reference)等等<attr name="circle_color" format="color"/></declare-styleable></resources>

对于自定义属性类型 & 格式如下:

<-- 1. reference:使用某一资源ID -->
<declare-styleable name="名称"><attr name="background" format="reference" />
</declare-styleable>
// 使用格式// 1. Java代码private int ResID;private Drawable ResDraw;ResID = typedArray.getResourceId(R.styleable.SuperEditText_background, R.drawable.background); // 获得资源IDResDraw = getResources().getDrawable(ResID); // 获得Drawble对象// 2. xml代码
<ImageViewandroid:layout_width="42dip"android:layout_height="42dip"app:background="@drawable/图片ID" /><--  2. color:颜色值 -->
<declare-styleable name="名称"><attr name="textColor" format="color" />
</declare-styleable>
// 格式使用
<TextViewandroid:layout_width="42dip"android:layout_height="42dip"android:textColor="#00FF00" /><-- 3. boolean:布尔值 -->
<declare-styleable name="名称"><attr name="focusable" format="boolean" />
</declare-styleable>
// 格式使用
<Buttonandroid:layout_width="42dip"android:layout_height="42dip"android:focusable="true" /><-- 4. dimension:尺寸值 -->
<declare-styleable name="名称"><attr name="layout_width" format="dimension" />
</declare-styleable>
// 格式使用:
<Buttonandroid:layout_width="42dip"android:layout_height="42dip" /><-- 5. float:浮点值 -->
<declare-styleable name="AlphaAnimation"><attr name="fromAlpha" format="float" /><attr name="toAlpha" format="float" />
</declare-styleable>
// 格式使用
<alphaandroid:fromAlpha="1.0"android:toAlpha="0.7" /><-- 6. integer:整型值 -->
<declare-styleable name="AnimatedRotateDrawable"><attr name="frameDuration" format="integer" /><attr name="framesCount" format="integer" />
</declare-styleable>
// 格式使用
<animated-rotatexmlns:android="http://schemas.android.com/apk/res/android"android:frameDuration="100"android:framesCount="12"/><-- 7. string:字符串 -->
<declare-styleable name="MapView"><attr name="apiKey" format="string" />
</declare-styleable>
// 格式使用
<com.google.android.maps.MapViewandroid:apiKey="0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" /><-- 8. fraction:百分数 -->
<declare-styleable name="RotateDrawable"><attr name="pivotX" format="fraction" /><attr name="pivotY" format="fraction" />
</declare-styleable>
// 格式使用
<rotatexmlns:android="http://schemas.android.com/apk/res/android"android:pivotX="200%"android:pivotY="300%"/><-- 9. enum:枚举值 -->
<declare-styleable name="名称"><attr name="orientation"><enum name="horizontal" value="0" /><enum name="vertical" value="1" /></attr>
</declare-styleable>
// 格式使用
<LinearLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"
/><-- 10. flag:位或运算 -->
<declare-styleable name="名称"><attr name="windowSoftInputMode"><flag name="stateUnspecified" value="0" /><flag name="stateUnchanged" value="1" /><flag name="stateHidden" value="2" /><flag name="stateAlwaysHidden" value="3" /><flag name="stateVisible" value="4" /><flag name="stateAlwaysVisible" value="5" /><flag name="adjustUnspecified" value="0x00" /><flag name="adjustResize" value="0x10" /><flag name="adjustPan" value="0x20" /><flag name="adjustNothing" value="0x30" /></attr>
</declare-styleable>、
// 使用
<activityandroid:name=".StyleAndThemeActivity"android:label="@string/app_name"android:windowSoftInputMode="stateUnspecified | stateUnchanged | stateHidden" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity><-- 特别注意:属性定义时可以指定多种类型值 -->
<declare-styleable name="名称"><attr name="background" format="reference|color" />
</declare-styleable>
// 使用
<ImageViewandroid:layout_width="42dip"android:layout_height="42dip"android:background="@drawable/图片ID|#00FF00" />

在自定义View的构造方法中解析自定义属性的值

/*** 此处是需要解析circle_color属性的值* 该构造函数需要重写*/ public CircleView(Context context, AttributeSet attrs) {this(context, attrs,0);// 原来是:super(context,attrs);init();public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);// 加载自定义属性集合CircleViewTypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CircleView);// 解析集合中的属性circle_color属性// 该属性的id为:R.styleable.CircleView_circle_color// 将解析的属性传入到画圆的画笔颜色变量当中(本质上是自定义画圆画笔的颜色)// 第二个参数是默认设置颜色(即无指定circle_color情况下使用)mColor = a.getColor(R.styleable.CircleView_circle_color,Color.RED);// 解析后释放资源a.recycle();init();}

在布局文件中使用自定义属性

/*** activity_main.xml*/
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"<!--必须添加schemas声明才能使用自定义属性-->xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="scut.carson_ho.diy_view.MainActivity"><!-- 注意添加自定义View组件的标签名:包名 + 自定义View类名--><!--  控件背景设置为黑色--><scut.carson_ho.diy_view.CircleViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#000000"android:padding="30dp"<!--设置自定义颜色-->app:circle_color="#FF4081"/>
</RelativeLayout>


至此,一个较为规范的自定义View已经完成了。

Android 完整的自定义View相关推荐

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

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

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

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

  3. Android进阶之自定义View实战(二)九宫格手势解锁实现

    一.引言 在上篇博客Android进阶之自定义View实战(一)仿iOS UISwitch控件实现中我们主要介绍了自定义View的最基本的实现方法.作为自定义View的入门篇,仅仅介绍了Canvas的 ...

  4. android 换行模式,Android进阶之自定义View(1)实现可换行的TextView

    今天来一起学习一下最简单的自定义view,自己动手写一个MyTextView,当然不会像系统的TextView那么复杂,只是实现一下TextView的简单功能,包括分行显示及自定义属性的处理,主要目的 ...

  5. android歌词效果,自定义View:Android歌词控件

    TicktockMusic 音乐播放器项目相关文章汇总: 简介 之前做 TicktockMusic 音乐播放器,一个必要的需求肯定是歌词,在 github 上找了几个,发现或多或少都有点不满足需求,所 ...

  6. Android弹性滑动在自定义View中的高级应用

    本文出自门心叼龙的博客,属于原创类容,转载请注明出处. 好久没有更新博客了,特意的看了博客最后的更新时间为2019年7月21日,今天是10月24日掐指一算已经有三个月时间了,自从上篇<开发杂谈: ...

  7. Android Study之自定义View进阶路:掌握绘制基本图形(一)

    LZ-Says:我觉得人与人相处,首先排在首位的是诚信,其次才是一些其他的东西.而关于技术,交流才是成长的路,闭门造车永远看不到外面的精彩,领悟不到自身新高度.So,诚信待人,多交流,多沟通,一起成长 ...

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

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

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

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

最新文章

  1. silverlight之How To:设置ComboBox控件的数据源当ComboBox用来作为DataGrid的某列的编辑控件时...
  2. caffe的python接口学习(6):用训练好的模型(caffemodel)来分类新的图片
  3. ExtJS学习笔记3:载入、提交和验证表单
  4. 透露抖音、腾讯、阿里、美团招开发岗位硬核面试题,轻轻松松收到offer
  5. KubeVela 上手|让云端应用交付更加丝滑
  6. [react] react与angular、vue有什么区别?
  7. Android_bug之Default Activity not found
  8. 送女朋友的java小程序_用C编写一个送给女朋友的情人节小程序 可爱!
  9. mac下安装wxPython2.8.12.1方法
  10. 25%的CPU利用率也能够让一台笔记本如此狼狈 (小红伞)
  11. Git和Gitlab协同工作
  12. 非常详细的图文安装wordpress安装教程
  13. 百度地图常用的几个webAPI(中文地址转经纬度,经纬度转中文地址)
  14. 兄弟Brother PT-9200DX 驱动
  15. android 高德地图录制视频,《高德地图》录制导航录音包方法教程
  16. C++ Primer Plus(嵌入式公开课)---第5,6章 循环和关系表达式 分支语句和逻辑运算符
  17. 离散数学计算机专业论文,计算机与离散数学论文.doc
  18. 使用Pygame开发flappy bird
  19. linux系统下文件的上传和下载(rz、sz)
  20. usb启动计算机boss设置方法,教程方法;U盘装系统中bios设置USB启动图文教程电脑技巧-琪琪词资源网...

热门文章

  1. ios-bug.html黑屏重启,iPhone大规模爆发黑屏无限重启bug!附解决方法
  2. 2021美赛题目翻译汇总
  3. 计算机毕业论文工作记录本,完整版)本科生毕业设计-工作记录本
  4. svn将分支branchs代码合并到主干trunk
  5. 知乎强烈推荐的5款手机APP,每一个都十分受用,你确定真的不需要吗
  6. 计算机中文字底纹咋操作,电脑word软件怎么为插入的表格设置底纹
  7. 互联网地址和域名系统
  8. 2021了,你还不会用 Electron 写一个桌面应用?
  9. 自然语言处理学习——论文分享——A Mutual Information Maximization Perspective of Language Representation Learning
  10. HTTPS,HTTP