关于自定义View,说简单有些效果很方便实现,说困难有些效果需要对View的整个原理有深入的研究,而且有时对自定义View这个概念就不是很理解。经过一些网上资料的查找以及对《Android开发艺术探索》和《Android进阶之光》等书籍的阅读,整理出部分知识点 简单总结一下自定义View相关知识。
什么是自定义View
我们平常需要一些比较炫酷、特殊的效果是系统中自带的控件无法实现的,这个时候就需要我们去继承View
或者ViewGroup
重写其中的某些相关方法,自己实现相关效果,也可以直接继承相关控件或者布局扩展其功能来实现我们想要的效果。
自定义View分类
自定义View分类标准不唯一,但是大致上可以分为四类:
-
直接继承View
这种的通常用于实现一些不规则的或者通过布局不易实现的效果再或者静态或者动态的显示一些不规则的图形。这个时候就可以直接继承自View
并重写onDrow()
方法来进行绘制。此时通常需要自己处理wrap_content
和padding
。如:绘制一个圆形,绘制雷达图等。 -
直接继承ViewGroup
这种主要用来实现某些除系统布局之外的特殊的布局方式。比如想将几个View
组合在一起的时候,便可以通过这种方式自定义相关布局。这种方式比继承View
实现起来稍复杂了一些。需要对相关元素进行测量和布局。 -
继承自某些控件
这种方式直接继承自某些已有控件如Button、TextView
等通常用来扩展已有的控件的功能,相比较于继承自View
的实现更加简单不需要自己处理wrap_content、padding
等 -
继承自某些布局
这种方式和直接继承ViewGroup
相比也是简便了一些,不需要自己再进行相关元素的测量和布局。当然离底层也稍微远一些。
自定义View中的重要方法
继承自View
-
构造函数
一共有四个构造函数,参数最多的构造函数是:public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
,最常用的只有前两个,相关含义:
context
:当前的上下文环境。
attrs
:可以通过该属性值得到自定义的declare-styleable
属性值。
declare-styleable
:当我们在布局文件中使用自定义View
并且想在该自定义View
中使用新的属性时可以在value文件夹下新建attrs.xml
文件为该自定义View
设置自定义的属性值。
相关代码
综上所述:我们可以在构造函数中初始化相关数据或者通过自定义attrs.xml
文件来为自定义View
设置相关属性然后在构造函数中得到该自定义属性值。 -
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
该方法用来测量View大小。其中的参数widthMeasureSpec
是由宽度大小以及宽度的测量模式组合而成的值。可以使用MeasureSpec
类的相关方法得到宽度的大小和测量模式,代码如下:
//得到宽度大小和其测量模式
widthSize=MeasureSpec.getSize(widthMeasureSpec);
widthMode=MeasureSpec.getMode(widthMeasureSpec);
//对View宽高进行修改
//setMeasuredDimension(widthSize,heightSize);
heightMeasureSpec
的含义同上。
在该方法中的到View宽高数据的同时也可以使用setMeasuredDimension(widthSize,heightSize);
方法来为View
设置宽度和高度大小
关于测量模式:
1.UNSPECIFIED
默认的测量模式,父控件没有给子View
任何限制,子View
可以设置为任意大小
2.EXACTLY
精确模式,表示父控件已经确切的指定了子View
的大小,对应于:直接指定宽高属性值或者match_parent
3.AT_MOST
最大模式,子View
大小没有具体限制,子View
最大为父View
大小,对应于:wrap_content
-
onSizeChanged(int w, int h, int oldw, int oldh)
该方法在View大小发生改变时调用。可以用来得到当前View的大小,该方法的四个参数含义:
1.w
当前View的宽度
2.h
当前View的高度
3.oldw
上一次View的宽度
4.oldh
上一次View的高度 -
onDraw(Canvas canvas)
该方法就是我们自定义View
中最常用也是最重要的方法,我们可以在该方法中绘制我们想要的View
图形。首先说明参数canvas
:画布,具有一系列与图形绘制相关的方法。
完成一个View
会依次经过以下绘制过程:
1.背景
使用drawBackground()
方法进行绘制,该方法不能重写
2.主体
使用onDraw()
方法进行绘制,该方法可重写
3.子View
使用dispatchDraw()
方法进行绘制,该方法可重写
4.滑动边缘渐变和滑动条
使用onDrawForeground()
方法进行绘制,该方法可重写
5.前景
使用onDrawForeground()
方法进行绘制,该方法可重写
所以我们可以通过重写相应的方法来控制View
绘制的顺序和绘制内容
相关代码
继承自ViewGroup
-
onLayout(boolean changed, int left, int top, int right, int bottom)
该方法主要用来确定子View
的布局位置,在自定义ViewGroup
时使用,调用子View
的layout
函数,用于确定子View
的位置。可以在该方法中调用相关方法实现对子View
的控制,如:
//子View个数
int count=getChildCount();
//子View对象
View child=getChildAt(0);
相关参数含义:
changed
:View
是否有新的位置和尺寸即是否改变
left
:子View
左侧距离父View
左侧的距离
top
:子View
顶部距离父View
顶部的距离
right
:子View
右侧距离父View
右侧的距离
bottom
:子View
底部距离父View
底部的距离
-
构造函数
同继承自View -
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
同继承自View -
onSizeChanged(int w, int h, int oldw, int oldh)
同继承自View -
onDraw(Canvas canvas)
同继承自View
绘制自定义View所使用的工具
Paint
画笔,顾名思义 该工具类主要是在图形绘制的过程中像一支笔一样与Canvas
以及Path
相配合用来辅助图形的绘制。只不过我们可以通过相关的方法来设置这支的颜色,粗细等属性。
示例:
mPaint=new Paint();
mPaint.setColor(Color.BLUE); //画笔颜色
mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
mPaint.setStrokeWidth(10f); //设置画笔宽度为10px
Canvas
画布,和画笔一样由名字便可得知它的作用,我们绘制图形便是在Canvas
上实现,可以与Paint和Path相互配合绘制出各种效果。该工具类为我们提供了:
基本图形
如:圆形、矩形、椭圆、点、线、圆弧等的绘制方法。
画布的相关操作
缩放、位移、旋转、设置显示区域等相关方法的实现。
基本图形绘制-部分相关代码
画布相关操作-部分相关代码
Path
路径,主要用来实现一些比点、线、圆、圆弧等更加复杂的操作。如:心形、正多边形、贝塞尔曲线等。
部分相关代码
如何为自定义View设置自定义属性
-
设置自定义属性,
attrs.xml
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomView">
<attr name="custom_view_color" format="color"/>
</declare-styleable>
</resources>
- 在自定义
View
中得到自定义属性的值:
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义属性值
TypedArray customViewAttrs=context.obtainStyledAttributes(attrs, R.styleable.CustomView);
int mColor=customViewAttrs.getColor(R.styleable.CustomView_custom_view_color, Color.RED);
}
- 使用自定义属性在布局文件中:
<com.example.androidprimarycodedemo.custom_view.CustomView
android:id="@+id/custom_view"
app:custom_view_color="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
实现自定义View步骤
通过上述一些知识的了解,我们大致可以得到自定义View
的大体步骤。
1、选定要继承的View类
分析要实现的效果确定要实现的自定义View
类需要继承自View
、ViewGroup
、特定控件还是特定的布局。
2、确定自定义View大小、位置等所需数据
根据实际情况确实是否需要处理wrap_content
、padding
以及通过相关函数的到实际需要的参数等。
3、根据具体情况进行绘制
根据要实现的效果选择相应的Paint
和Path
以及Canvas
的一些效果进行自定义View
的绘制。
自定义View注意事项
-
让View支持wrap_content
直接继承自View
和ViewGrop
的自定义View
如果不在onMeasure
中对wrap_content
进行特殊处理,当外界布局使用wrap_content
属性时将无法达到预期效果。 -
如果有必要,让你的View支持padding
直接继承自View
的控件如果不在draw
中处理padding
,则padding
属性无法起作用,继承自ViewGroup
的控件需要在onMeasure
和onLayout
中考虑padding
和子元素的margin
对其造成的影响,否则将导致padding
和子元素的margin
失效。 -
尽量不要再View中使用Handler,没必要
View
内部提供了post
系列方法可以替代Handler
的作用。 -
View中如果有线程和动画,需要及时停止
当View
中带有线程或者动画时最好在onAttachedToWindow
方法调用时是启动,在onDetachedFromWindow
方法调用时停止,防止造成内存泄漏。 -
View带有滑动嵌套冲突情形时,需要处理好滑动冲突
滑动冲突如果不能处理好则会影响View的效果。
上述 自定义View分类和自定义View注意事项 内容摘抄自《Android开发艺术探索》
网友评论