美文网首页
Android开发(16)——自定义绘制

Android开发(16)——自定义绘制

作者: 让时间走12138 | 来源:发表于2021-04-01 11:07 被阅读0次

    本节内容

    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
        }
    
    • 半径:如果长>宽,那么半径为宽/2。否则为长/2
    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

    相关文章

      网友评论

          本文标题:Android开发(16)——自定义绘制

          本文链接:https://www.haomeiwen.com/subject/ybnghltx.html