Android自定义View
来源:互联网 发布:淘宝助手数据包 编辑:程序博客网 时间:2024/06/04 05:53
内容会很多哦。如果这节自定义View描述有什么错误的地方,麻烦指正一下。
如果不懂的同学,希望你们耐心看完本章节。我也是刚入门的。好了,废话不多说!!
Android自定义View 是什么?
顾名思义,自定义View就是我们自己定义的View,并且能和用户进行交互的控件。我们使用的button都是继承view这个父类的。当安卓内置的View不足以满足我们日常的开发需求的时候,我们就可以通过自定义View来实现自己想要的效果。比如如下图所示,跳过显示广告网页直接进入主界面的按钮。
涉及到的类和方法?
onDraw():是View显示界面的方法,在这个方法的内部进行描绘你想要的效果。一般都会涉及到几个比较重要的类。
Paint 画笔类,设置画笔的粗细,颜色等属性
Canvas 画布类,提供各种画各种图形的api
Bitmap 位图类,用来获取图片的信息。
matrix 矩阵类,用来控制图片的现实
View的绘制流程
假设一辆车的生产过程。
测量车的框架大小,根据车的框架大小来测量车内饰大小的,比如座位等。onMeasure()
开始定制,根据测量的尺寸来进行生产。onDraw()
生产完成之后,将需要的东西填充到框架里去。onLayout()
最后,该车具备了走的功能了,我们就能使用它了。onTouch() 用于和用户进行交互
初步使用?
首先我创建一个类,RectView类。这个类需要继承自View。其次覆写里面的方法,在这里我们覆写前面两种方法。
public class RectView extends View { public RectView(Context context) { super(context); } public RectView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); }}
我们首先简单的画一个矩形。此时我们需要覆写onDraw()方法。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //创建一个矩形区域,里面的数字分别代表 left,top,right,bottom RectF rectF = new RectF(0, 0, 100, 100); //创建一个画笔 Paint paint = new Paint(); //用画布画出一个矩形 canvas.drawRect(rectF, paint); }
然后添加一下xml的标签,相当于添加一个button按钮这样。
<com.example.does.customview.RectView android:layout_width="wrap_content" android:layout_height="wrap_content" />
然后Run,这样矩形就画出来了。
onDraw(Canvas canvas)中的canvas相当于画布,不了解的话可以百度一下。理解为一张画布就行了。Paint()这个就是创建一个画笔,RectF()中的Rect代表的意思是矩形,F代表的float类型,可以Ctrl点进去看源码就知道了。
Canvas这个类里面有许多方法,比如画一个圆。我们修改一下,
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //创建一个矩形区域,里面的数字分别代表 left,top,right,bottom RectF rectF = new RectF(0, 0, 500, 500); //创建一个画笔 Paint paint = new Paint(); //用画布画出一个圆 canvas.drawOval(rectF,paint); }
效果如下,
当然,我们还可以对其描绘的东西做其它属性的修改,
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //创建一个矩形区域,里面的数字分别代表 left,top,right,bottom RectF rectF = new RectF(10, 10, 500, 500); //创建一个画笔 Paint paint = new Paint(); //抗锯齿 paint.setAntiAlias(true); //设置一个空心圆 paint.setStyle(Paint.Style.STROKE); //设置画笔的颜色 paint.setColor(Color.BLUE); //设置外边粗一点 paint.setStrokeWidth(5); //用画布画出一个圆 canvas.drawOval(rectF,paint); }
具体更多的属性,自己自定的过程中再摸索其里面更多的方法。这里再多做演示了。
自定义控件view覆写方法的调用顺序
添加需要实现的其它方法,并且Log日志打印
public class RectView extends View { public RectView(Context context) { super(context); } public RectView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.i("does", "onDraw: "); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.i("does", "onMeasure: "); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.i("does", "onLayout: "); }}
运行,看输出日志
07-15 12:37:22.155 3907-3907/com.example.does.customview I/does: onMeasure:
07-15 12:37:22.328 3907-3907/com.example.does.customview I/does: onMeasure:
07-15 12:37:22.329 3907-3907/com.example.does.customview I/does: onLayout:
07-15 12:37:22.388 3907-3907/com.example.does.customview I/does: onMeasure:
07-15 12:37:22.388 3907-3907/com.example.does.customview I/does: onLayout:
07-15 12:37:22.388 3907-3907/com.example.does.customview I/does: onDraw:
显示测量两次,显示,再测量,最后绘画。
为什么这样?因为我们自定义View添加到xml布局文件里面去的,系统是先测量我们自定义控件的,宽度高度,然后再测量父控件的宽度高度,然后为了保险一点,系统再次测量我们的自定义控件的高度,最后再画出来。
onMeasure()方法讲解
我们先用一个实例看看具体有什么样的效果。
我在onDraw()里给canvas画一个颜色,然后在xml里面添加两个宽高属性,都是warp_content
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.BLUE); }
<com.example.does.customview.RectView android:layout_width="wrap_content" android:layout_height="wrap_content" />
运行,效果如下。
如果我再修改xml的属性,将高度改成50dp,出现的是这样的效果,
<com.example.does.customview.RectView android:layout_width="wrap_content" android:layout_height="50dp" />
接着,我们在onMeasure方法里添加一行代码
setMeasuredDimension(100,100);
最终的效果是这样的
神奇吧 ?!! 哈哈。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
1.widthMeasureSpec
2.heightMeasureSpec
Log日志输入看看分别是什么值,将setMeasuredDimension(100,100);这行代码注释掉。
07-15 14:26:39.508 31129-31129/com.example.does.customview I/does: onMeasure: -2147482568
07-15 14:26:39.508 31129-31129/com.example.does.customview I/does: onMeasure: 1073741955
数值是什么我们暂且不管它。
这两个参数分别都是由两个int类型构成的。我们创建一个变量抽离出来,
int widethMode = MeasureSpec.getMode(widthMeasureSpec); int widethSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec);
打印log日志,
07-15 14:35:35.704 3319-3319/com.example.does.customview I/does: heightMode: 1073741824 widthMode-2147483648
07-15 14:35:35.704 3319-3319/com.example.does.customview I/does: heightSize: 131 widthSize1080
数值我们也暂且不管它。
我们看看getMode里面的源码,源码里定义了三个变量,分别是
- AT_MOST 表示父控件对自定义控件的最大值
- EXACTLY 表示父控件对自定义控件的精确值
UNSPECIFIED 表示父控件对自定义控件大小无限制 比如listview
log打印输出,
07-15 14:42:04.036 3319-3319/com.example.does.customview I/does: heightMode: 1073741824 widthMode-2147483648
07-15 14:42:04.036 3319-3319/com.example.does.customview I/does: heightSize: 131 widthSize1080
07-15 14:42:04.036 3319-3319/com.example.does.customview I/does: UNSPECIFIED : 0
07-15 14:42:04.036 3319-3319/com.example.does.customview I/does: AT_MOST : -2147483648
07-15 14:42:04.036 3319-3319/com.example.does.customview I/does: EXACTLY : 1073741824
为了验证这三个值,我们在onMeasure()方法里添加switch语句。
switch (widthMode){ case MeasureSpec.UNSPECIFIED: Log.i("does", "UNSPECIFIED : "+ MeasureSpec.UNSPECIFIED); break; case MeasureSpec.AT_MOST: Log.i("does", "AT_MOST : "+ MeasureSpec.AT_MOST ); break; case MeasureSpec.EXACTLY: Log.i("does", "EXACTLY : "+ MeasureSpec.EXACTLY ); break; default: break; }
然后运行,发现输出语句
07-16 01:19:06.835 5190-5190/com.example.does.customview I/does: heightMode: 1073741824 widthMode-2147483648
07-16 01:19:06.835 5190-5190/com.example.does.customview I/does: heightSize: 131 widthSize1080
07-16 01:19:06.835 5190-5190/com.example.does.customview I/does: AT_MOST : -2147483648
此时输出的是AT_MOST的值。
如果我们将布局文件里,我们自定义属性的宽高的wrap_content改成固定的值,输出的则是EXACTLY。精确值嘛,有确定的值。
那UNSPECIFIED呢?如果我们的父控件改成用scrollview,那么输出的值便是UNSPECIFIED。
onLayout()方法讲解
该方法是提供给ViewGroup来放置每个子控件的。通常我们需要配onMeasure来一起使用。
这个方法是每次布局大小变化,或者位置改变的时候都会本调用。
onLayout(boolean changed, int l, int t, int r, int b) changed 这个控件是否更改位置或者尺寸了
l 相对于父控件的左边的位置
t 相对于父控件的顶部的位置
r 相对于父控件的右边的位置
b 相对于父控件的下部的位置
我们必须在这个方法内部将子控件有序的放置在合适的位置。View 提供了llayout(int l, int t, int r, int b)方法给我们。
- Android View---自定义View
- Android View---自定义View
- Android 自定义View 之 自定义View属性
- 【自定义View系列】android自定义View概述
- Android自定义view自定义属性
- Android自定义控件 -- 自定义View
- android自定义view(自定义数字键盘)
- Android自定义View-自定义属性
- Android自定义View-自定义属性
- Android 自定义View
- Android 自定义 View
- android自定义View
- Android 中自定义 view
- android 自定义view组件
- Android 自定义 View
- android 自定义view
- Android:如何自定义View
- android 自定义View
- 关于数据结构的学习
- const的用法,特别是用在函数前面与后面的区别
- 样本标准差
- 开机自启动:从busybox到debian
- springmvc的两个处理器适配器(四)
- Android自定义View
- 一、android studio JNI 的简单编写使用。
- Keil中Use MicroLIB的作用
- spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题
- android硬件 NFC开发
- app中蓝牙开启与关闭
- PCSHANGPython3连接MariaDB
- pymsql excute_many 出现 not all arguments converted with on duplicate key update
- visual studio code 简介