Android自定义控件

在Android中,无论是熟知的布局,还是控件,统统全都继承自基类View。

自定义View实现有几种:

① 自定义组合控件:多个控件组合成为一个新的控件,方便多处复用② 继承系统View控件:继承自TextView等系统控件,在系统控件的基础功能上进行扩展③ 继承View:不复用系统控件逻辑,继承View进行功能定义④ 继承系统ViewGroup:继承自LinearLayout等系统控件,在系统控件的基础功能上进行扩展⑤ 继承ViewGroup:不复用系统控件逻辑,继承ViewGroup进行功能定义
一、View的绘制流程

View的绘制基本由measure()、layout()、draw()这个三个函数完成:

measure:测量View的宽高,主要是View中的:measure(),setMeasuredDimension(),onMeasure()方法。layout:计算当前View以及子View的位置,主要是View中的:layout(),onLayout(),setFrame()方法。draw:视图的绘制工作,主要是View中的:draw(http://daduchang.net/433911.html),onDraw()方法。
二、Android 屏幕坐标系

在Android坐标系中,以屏幕左上角作为原点,这个原点向右是X轴的正轴,向下是Y轴正轴。

根据以上的坐标,结合View基类的相关API,涉及View的一些坐标方法,比如:

getTop:View到其父布局顶边的距离getLeft:http://daduchang.net/433909.htmlView到其父布局左边的距离getBottom:View到其父布局顶边的距离getRight:View到其父布局左边的距离
结合以上的API,可以计算出视图的宽度和高度,可以使用如下方式计算:

width = getRight - getLeft;height =http://daduchang.net/433912.html getBottom - getTop
三、自定义View开发的步骤

这里我们介绍最复杂的一种,自定义View。

3.1 构造函数

无论是继承系统View还是直接继承View,都需要对构造函数进行重写,构造函数有多个,至少要重写其中一个才行。

public class CustomView extends View{

/**

  • 代码中New实例化时 调用该方法

*/

public CustomView(Context context){

super(context);

}

/**

  • 在xml布局文件中使用时会自动调用该方法

*/

public CustomView(Context context, AttributeSet attrshttp://daduchang.net/433913.html){

super(context, attrs);

}

//更多参数的构造函数

}

3.2 自定义属性

Android系统的控件以android开头的都是系统自带的属性。为了方便配置自定义View的属性,我们也可以自定义属性值。Android自定义属性可分为以下几步:

1、自定义一个View2、编写values/attrs.xml,在其中编写styleable和item等标签元素3、在布局文件中View使用自定义的属性(注意namespacehttp://daduchang.net/433914.html)4、在View的构造方法中通过TypedArray获取
attrs.xml文件示例如下:

<?xml version="1.0" encoding="utf-8"?>

代码实现示例如下:

public class MyTextView extends View {

private static final String TAG = MyTextView.class.getSimpleName();

//在View的构造方法中通过TypedArray获取

public MyTextView(Context context, AttributeSet attrshttp://daduchang.net/433915.html) {

super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test);

String text = ta.getString(R.styleable.test_testAttr);

int textAttr = ta.getInteger(R.styleable.test_text, -1);

Log.e(TAG, "text = " + text + " , textAttr = " + textAttr);

ta.recycle();

}

}

布局文件使用示例如下:

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:tools=“http://schemas.android.com/tools”

xmlns:app=“http://schemas.android.com/apk/res/com.example.test”

android:layout_width=“match_parent”

android:layout_height=“match_parent” >

<com.example.test.MyTextView

android:layout_width=“100dphttp://daduchang.net/433916.html

android:layout_height=“200dp”

app:testAttr=“520”

app:text=“helloworld” />

四、Measure()

MeasureSpec

MeasureSpec是View的内部类,它封装了一个View的尺寸,在onMeasure()当中会根据这个MeasureSpec的值来确定View的宽高。MeasureSpec的值保存在一个int值当中。一个int值有32位,前两位表示模式mode后30位表示大小size。即MeasureSpec = mode + size。

在MeasureSpec当中一共存在三种mode:

UNSPECIFIED:无限制,View对尺寸没有任何限制,View设置为多大就应当为多大。EXACTLY :精准模式,View需要一个精确值,这个值即为MeasureSpec当中的Size。对应的是match_parent。AT_MOST:最大模式,View的尺寸有一个最大值,View不可以超过MeasureSpec当中的Size值。对应的是wrap_content。
常见的使用方式如下:

// 获取测量模式(Mode)

int specMode =http://daduchang.net/433917.html MeasureSpec.getMode(measureSpec)

// 获取测量大小(Size)

int specSize = MeasureSpec.getSize(measureSpec)

// 通过Mode 和 Size 生成新的SpecMode

int measureSpec=MeasureSpec.makeMeasureSpec(size, mode);

onMeasure

整个测量过程的入口位于View的measure方法当中,该方法做了一些参数的初始化之后调用了onMeasure方法,这里我们主要分析onMeasure。onMeasure源码如下:

protected void onMeasurehttp://daduchang.net/433918.html(int widthMeasureSpec, int heightMeasureSpec) {

setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),

getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));

}

setMeasuredDimension(int measuredWidth, int measuredHeight) :该方法用来设置View的宽高,在我们自定义View时也会经常用到。getDefaultSize(int size, int measureSpec):该方法用来获取View默认的宽高。getSuggestedMinimumWidth():getHeight和该方法原理是一样的
五、Layout()

layout()过程,对于View来说用来计算Viewhttp://daduchang.net/433919.html的位置参数,对于ViewGroup来说,除了要测量自身位置,还需要测量子View的位置。layout()方法是整个Layout()流程的入口,并在layout方法中调用了onLayout方法,主要是进行子View的计算。

六、Draw()

draw流程也就是的View绘制到屏幕上的过程,整个流程的入口在View的draw()方法之中,而源码注释也写的很明白,整个过程可以分为6个步骤:

绘制背景有过有必要,保存当前canvas绘制View的内容绘制子View根据需要,绘制边缘、阴影等效果绘制装饰,如滚动条等等
七、总结

自定义View在Androidhttp://daduchang.net/433920.html的开发中的重要性还是很大的,因为仅仅靠系统提供的控件和组件,无论是美观度还是使用度,再或者是新特性上,都无法满足特定的业务场景。因此,常常要用到自定义View,这就要求要在自己的项目自己完成特殊控件的自主开发。自定义控件在开发过程中也属于重点和难点,应该多花时间进行学习和研究,重点有以下几个:

控件属性的定义、设置和使用交互处理:事件交互和处理属于重中之重,常常要和事件分发结合在一起研究。Canvas和Paint:在进行自定义View开发时,往往会通过画布自己使用画笔进行绘制,这就要求要对Paint、Path、Canvas要做着重的掌握。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
封面 1 序 2 捐助说明 5 目 录 7 第一章 View的绘图流程 12 1.1、概述 12 1.2、Activity的组成结构 13 1.3、View树的绘图流程 15 1.3.1 测量组件大小 16 1.3.2 确定子组件的位置 17 1.3.3 绘制组件 18 1.4、说点别的 22 1.5 练习作业 22 第二章 Graphics2D API 23 2.1、概述 23 2.2、Point类和PointF类 23 2.3、Rect类和RectF类 25 2.4、Bitmap类和BitmapDrawable类 32 2.5、Canvas类与Paint类 34 2.5.1 绘图概述 34 2.5.2 Paint类 34 2.5.3 Canvas类 39 2.6 练习作业 63 第三章 使用Graphics2D实现动态效果 64 3.1 概述 64 3.2 invalidate()方法 65 3.3 坐标转换 69 3.4 剪切区(Clip) 73 3.5 案例:指针走动的手表 82 3.6 练习作业 88 第四章 双缓存技术 89 4.1 双缓存 89 4.2 在屏幕上绘制曲线 90 4.3 在屏幕上绘制矩形 99 4.4 案例:绘图App 104 4.4.1 绘图属性 106 4.4.2 软件参数 108 4.4.3 绘图缓冲区 109 4.4.4 撤消操作 111 4.4.5 图形绘制 113 4.4.6 绘图区 118 4.4.7 主界面 119 4.5 练习作业 122 第五章 阴影、渐变和位图运算 123 5.1 概述 123 5.2 阴影 123 5.3 渐变 125 5.3.1 线性渐变(LinearGradient) 126 5.3.2 径向渐变(RadialGradient) 130 5.3.3 扫描渐变(SweepGradient) 135 5.3.4 位图渐变(BitmapShader) 138 5.3.5 混合渐变(ComposeShader) 140 5.3.6 渐变与Matrix 142 5.4 位图运算 143 5.4.1 PorterDuffXfermode 143 5.4.2 图层(Layer) 146 5.4.3 位图运算技巧 148 5.5 案例1:圆形头像 152 5.6 案例2:刮刮乐 156 5.7 练习作业 161 第六章 自定义组件 163 6.1 概述 163 6.2 自定义组件的基本结构 164 6.3 重写onMeasure方法 166 6.4 组件属性 175 6.4.1 属性的基本定义 175 6.4.2 读取来自style和theme中的属性 181 6.5 案例1:圆形ImageView组件 186 6.6 案例2:验证码组件CodeView 190 6.7 练习作业 202 第七章 自定义容器 204 7.1 概述 204 7.2 ViewGroup类 205 7.2.1 ViewGroup常用方法 205 7.2.2 ViewGroup的工作原理 208 7.2.3 重写onLayout()方法 213 7.3 CornerLayout布局 217 7.3.1 基本实现 217 7.3.2 内边距padding 224 7.3.3 外边距margin 228 7.3.4 自定义LayoutParams 238 7.4 案例:流式布局(FlowLayout) 246 7.5 练习作业 256 第八章 Scroller与平滑滚动 257 8.1 概述 257 8.2 认识scrollTo()和scrollBy()方法 258 8.3 Scroller类 264 8.4 平滑滚动的工作原理 271 8.5 案例:触摸滑屏 272 8.5.1 触摸滑屏的技术分析 272 8.5.2 速度跟踪器VelocityTracker 273 8.5.3 触摸滑屏的分步实现 274 8.6 练习作业 285 第九章 侧边栏 287 9.1 概述 287 9.2 使用二进制保存标识数据 289 9.2.1 位运算符 289 9.2.2 位运算的常用功能 292 9.3 继承自ViewGroup的侧边栏 293 9.4 继承自HorizontalScrollView的侧边栏 304 9.5 练习作业 312 第十章 加强版ListView 313 10.1 概述 313 10.2 ListView的基本使用 314 10.3 ListItem随手指左右滑动 318 10.4 向右滑动删除ListItem 326 10.5 滑动ListItem出现删除按钮 336 10.5.1 列表项专用容器ExtendLayout 337 10.5.2 列表项能滑出删除按钮的ListView 342 10.5.3 定义布局文件 350 10.5.4 显示ListView 351 10.6练习作业 353 案例代码说明 354

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值