Android学习笔记-自定义View-基础知识

关于自定义View,说简单有些效果很方便实现,说困难有些效果需要对View的整个原理有深入的研究,而且有时对自定义View这个概念就不是很理解。经过一些网上资料的查找以及对《Android开发艺术探索》《Android进阶之光》等书籍的阅读,整理出部分知识点 简单总结一下自定义View相关知识。

什么是自定义View

我们平常需要一些比较炫酷、特殊的效果是系统中自带的控件无法实现的,这个时候就需要我们去继承View或者ViewGroup重写其中的某些相关方法,自己实现相关效果,也可以直接继承相关控件或者布局扩展其功能来实现我们想要的效果。

自定义View分类

自定义View分类标准不唯一,但是大致上可以分为四类:

  • 直接继承View
    这种的通常用于实现一些不规则的或者通过布局不易实现的效果再或者静态或者动态的显示一些不规则的图形。这个时候就可以直接继承自View并重写onDrow()方法来进行绘制。此时通常需要自己处理wrap_contentpadding。如:绘制一个圆形,绘制雷达图等。
  • 直接继承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时使用,调用子Viewlayout函数,用于确定子View的位置。可以在该方法中调用相关方法实现对子View的控制,如:
        //子View个数
        int count=getChildCount();
        //子View对象
        View child=getChildAt(0);

相关参数含义:
changedView是否有新的位置和尺寸即是否改变
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类需要继承自ViewViewGroup、特定控件还是特定的布局。
2、确定自定义View大小、位置等所需数据
根据实际情况确实是否需要处理wrap_contentpadding以及通过相关函数的到实际需要的参数等。
3、根据具体情况进行绘制
根据要实现的效果选择相应的PaintPath以及Canvas的一些效果进行自定义View的绘制。

自定义View注意事项

  • 让View支持wrap_content
    直接继承自ViewViewGrop的自定义View如果不在onMeasure中对wrap_content进行特殊处理,当外界布局使用wrap_content属性时将无法达到预期效果。
  • 如果有必要,让你的View支持padding
    直接继承自View的控件如果不在draw中处理padding,则padding属性无法起作用,继承自ViewGroup的控件需要在onMeasureonLayout中考虑padding和子元素的margin对其造成的影响,否则将导致padding和子元素的margin失效。
  • 尽量不要再View中使用Handler,没必要
    View内部提供了post系列方法可以替代Handler的作用。
  • View中如果有线程和动画,需要及时停止
    View中带有线程或者动画时最好在onAttachedToWindow方法调用时是启动,在onDetachedFromWindow方法调用时停止,防止造成内存泄漏。
  • View带有滑动嵌套冲突情形时,需要处理好滑动冲突
    滑动冲突如果不能处理好则会影响View的效果。

上述 自定义View分类和自定义View注意事项 内容摘抄自《Android开发艺术探索》

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

推荐阅读更多精彩内容