本节内容
1.View和ViewGroup重写创建方法的区别
2.创建类继承于View实现构造方法
3.重写创建方法
4.绘制背景色
5.drawCircle()画圆
6.Paint设置颜色的三种方式
7.drawBitmap画图和DrawPath
8.绘制线和贝塞尔曲线
9.画圆弧和圆
一、View和ViewGroup重写创建方法的区别
1.自定义一个控件 只需要直接或间接继承于view
2.View绘制的流程:onMeasure() 测量,onDraw() 绘制
3.ViewGroup绘制的流程:onMeasure() 测量, onLayout() 布局,onDraw() 绘制,多数情况下不需要实现onDraw方法。
4.对于单个view来说,只需要负责好自己的事情,比如自己的宽高等。但是对于ViewGroup来说,还需要对子视图进行布局。主要 负责怎么布局。
二、创建类继承于View实现构造方法
1.自定义ViewGruop:组合或者自定义规则(系统没有定义的规则,比如流式布局)
2.自定义View:在已有控件基础上自定义(比如在图片上额外添加水印),自定义绘制(画系统里面没有的形状)
3.创建一个类继承于View 或者View的子类,重写构造方法 (主要的3个)
public class CustomView extends View {
//使用代码创建控件
public CustomView(Context context) {
super(context);
Log.v("swl","代码创建,只需要一个context");
}
//使用xml配置 AttributeSet xml中配置的属性
public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
Log.v("swl","xml创建 context和AttributeSet");
}
//xml 样式
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
4.如果使用xml配置,那么就会调用第二个方法,然后在layout中添加一个控件,并配置一些属性
<com.example.customdraw.CustomView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"/>
5.如果使用代码来创建,那么直接调用这个类的方法即可,这里调用的是第一种构造方法。
CustomView(this)
6.用kotlin的方式创建一个类, Kotlin中如果一个类继承另外一个类 并且父类中有多个构造方法 就使用参数最多的那个构造方法来构建父类
class CustomViewKt(context:Context,attrs:AttributeSet?,defStyleAttr:Int):View(context,attrs,defStyleAttr) {
}
然后提供参数比较少的那几个构造方法作为次构造方法。
//代码创建
constructor(context: Context):this(context,null,0){
Log.v("swl","代码创建 context ")
}
//xml创建
constructor(context: Context,attrs: AttributeSet?):this(context,attrs,0){
Log.v("swl","xml创建 context 和attributeSet")
}
7.在代码中使用一下这个自定义View
CustomViewKt(this)
三、重写创建方法
1.重写onMeasure方法
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
2.绘制draw(),绘制主体内容
override fun onDraw(canvas: Canvas?) {
}
3.如果是ViewGroup,还要绘制子视图。
override fun dispatchDraw(canvas: Canvas?) {
super.dispatchDraw(canvas)
}
4.绘制前景
override fun onDrawForeground(canvas: Canvas?) {
super.onDrawForeground(canvas)
}
5.测量完view的宽高之后,就会回调 onSizeChanged()方法,在onMeasure()方法之后调用。
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
}
四、绘制背景色
1.在onDraw里面绘制内容,想要绘制,有四部分必不可少
-
Bitmap : 图片
-
画板: Canvas 绘制类 提供各种绘制的方法 drawXXX 线、点、矩形、圆
-
画笔:Paint 确定画笔的粗细 颜色
-
画的内容:Path
2.当重写父类的方法时,如果父类空实现,子类可以不调用super.method()。如果父类有具体的实现 ,通常都是先调用super.method(),再实现自己的。
3.在onDraw()方法里面绘制背景颜色
setBackgroundColor(Color.MAGENTA)
-
Color 管理颜色的类 默认提供了一些常用颜色
-
如果不喜欢系统为我们设定好的颜色,可以自己传一个颜色过去(16进制的颜色代码)
setBackgroundColor(Color.parseColor("#B990E7"))
五、drawCircle()画圆
1.画一个圆需要,drawCircle(cx,cy)中心点的坐标, radius 半径,paint 画笔。
2.注意onDraw方法会被多次调用,重复调用,在这个方法里面尽量不要创建对象。
3.首先我们要得到圆心的坐标,它在矩形的正中间,也就是说我们需要得到矩形的宽和高。我们定义几个全部变量来记录视图的尺寸。
private var mWidth= 0
private var mHeight= 0
private var raidus= 0f
4.然后在onSizeChanged()方法里面获取尺寸
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
//获取尺寸
mWidth=measuredWidth
mHeight=measuredHeight
raidus = if(mWidth>mHeight) mHeight/2f else mWidth/2f
}
5.创建圆的画笔,使用懒加载的方式。填充方式 stroke描边 FILL 填充 STROKE_FILL 都有
private val circlePaint:Paint by lazy {
Paint().apply {
color=Color.MAGENTA
style= Paint.Style.FILL
//画笔粗细
strokeWidth = 5f
}
}
6.然后在onDraw()方法里面绘制一个圆
canvas?.drawCircle(mWidth/2f,mHeight/2f,radius,circlePaint)
六、Paint设置颜色的三种方式
color=Color.MAGENTA
color = Color.parseColor("#12321D")
setARGB(255,175,202,253)
1.以上是设置画笔颜色的几种方法,最后一种方法的第一个参数为透明度,后面三个参数为rgb。
2.shader:着色器。子类,LinearGradient 线性渐变色。
-
x0,y0渐变起始点 x1,y1渐变终点 color0,color1 渐变色。(调用该方法时,各参数的含义)
-
tile :Shader.TileMode CLAMP :边缘色拉伸 ,REPEAT :重复 ,MIRROR:倒影(主要是用来填满空白部分,由于图片的规格,所以它有可能铺不满我们那个圆,所以需要把它填满)
-
举例,以下代码表示从上至下的渐变,那么x的坐标就可以随便设置,y的坐标由0到容器的高度
shader= LinearGradient(mWidth/2f,0f,mWidth/2f,mHeight.toFloat(),
Color.BLUE,Color.GREEN,
Shader.TileMode.CLAMP
)
3. Bitmap:就是具体图片。res.drawable.1.jpg是图片对应的ID,这个id对应的图片的真实数据就是Bitmap
val img= BitmapFactory.decodeResource(resources,R.drawable.cute2)
shader= BitmapShader(img,Shader.TileMode.REPEAT,Shader.TileMode.CLAMP)
七、drawBitmap画图和DrawPath
1.获取id对应的真实图片
private val logo:Bitmap by lazy {
BitmapFactory.decodeResource(resources,R.drawable.cute2)
}
2.用drawBitmap绘制图片,logo是图片变量。中间两个参数是图片放置的位置坐标。(图片左上角的坐标)
canvas?.drawBitmap(logo,(mWidth-logo.width)/2f,(mHeight-logo.height)/2f,circlePaint)
3.用drawLine画线,需要起点(x0,y0)和终点(x1,y1),可以画横线竖线和斜线。
canvas?.drawLine(20f,0f,300f,0f,circlePaint)
canvas?.drawLine(140f,0f,140f,300f,circlePaint)
canvas?.drawLine(20f,300f,300f,300f,circlePaint)
4.画线,通过path 确定路径绘制这个path,moveTo :设置路径的起点。lineTo:设置路径的终点。
val path= Path().apply {
moveTo(20f,30f)
lineTo(400f,30f)
moveTo(210f,30f)
lineTo(210f,300f)
moveTo(20f,300f)
lineTo(400f,300f)
}
canvas?.drawPath(path,circlePaint)
八、绘制线和贝塞尔曲线
1.二阶贝塞尔曲线,画一个圆弧(右半圆)。前两个参数为弧最远的点的坐标,后两个参数为弧终点的坐标。
quadTo(600f,450f,400f,600f)
moveTo(100f,800f)
image.png
2.三阶贝塞尔曲线。
cubicTo(300f,500f,700f,1100f,900f,800f)
3.有两个弧,有点类似于正弦曲线,前两个参数为第一个转折点坐标,中间两个参数为第二个转折点坐标,最后两个参数为终点坐标。
cubicTo(300f,500f,700f,1100f,900f,800f)
image.png
九、画圆弧和圆
1.RectF是为了确定一个圆,这四个参数分别代表圆的左上右下四个参数。也就是圆的左上右下四个点与屏幕之间的距离。
2.acrTo是确定圆弧扫过的范围,这里是从0到-90°。close()表示闭合一下。画出来就如下图所示。
moveTo(500f,400f)
val rect= RectF(100f,0f,900f,800f)
arcTo(rect,0f,-90f)
close()
image.png
4.画个圆,前两个参数x和y表示中心点坐标,第三个参数表示圆的半径,最后一个参数是画圆时的轨迹是顺时针还是逆时针,CW表示顺时针,CCW表示逆时针。
addCircle(500f,800f,300f,Path.Direction.CW)
image.png
网友评论