Android中使用Canvas和Paint实现自定义View

一、简述

对于自定义View的实现,Canvas和Paint两类是很有用的。
这两个类是 android.graphics 包下的两个类,Canvas是画布,Paint是画笔,通过这两者结合一起,就可以绘制出自己需要的View,然后将View加入到布局 xml 中或者在 Java 代码中引用即可。

二、基本步骤

(一)创建一个自定义的MyView继承View
(二)创建MyView的三个构造方法

  • MyView(Context context)
  • MyView(Context context,AttributeSet attributeSet)
  • MyView(Context context, AttributeSet attributeSet,int defStyleAttr)

(三)重写View.onDraw()方法,添加自己的绘制逻辑
(四)在Java代码中引用或者加入到XML布局中

三、具体步骤

(一)创建一个自定义MyView继承View

public class MyView extends View {

    }

(二)创建MyView的三个构造函数

    //当Java代码中创建MyView时调用,如setContentView(new MyView(this))
    public MyView(Context context) {
        super(context);
    }
    //当在XML中引入MyView时候调用
    public MyView(Context context, AttributeSet attributeSet)
    {
        super(context,attributeSet);
    }
    //这个构造函数一般不会主动调用
    public MyView(Context context,AttributeSet attributeSet,int defStyleAttr)
    {
        super(context,attributeSet,defStyleAttr);
    }

Tips:注意三个构造函数的区别,在不同的情况调用不同的构造函数

(三)重写View.onDraw()方法

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //这里添加自己的绘制逻辑
    }

(四)在Java代码中引用或者加入到XML布局中

1、 在Java代码中引用

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
}   

2、在XML布局中引入

XML的布局 activity_main

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.example.hasee.clockviewdemo.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

Java中加载布局activity_mian

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

四、实例(画一个圆)

完整代码如下:

自定义MyView部分

package com.example.hasee.clockviewdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class MyView extends View {

    private Paint mPaint = new Paint();
    /*三种构造方法*/
    public MyView(Context context) {
        super(context);
        Log.v("MyView","构造函数1 被调用");
        init();
    }
    public MyView(Context context, AttributeSet attributeSet)
    {
        super(context,attributeSet);
        Log.v("MyView","构造函数2 被调用");
        init();
    }
    public MyView(Context context,AttributeSet attributeSet,int defStyleAttr)
    {
        super(context,attributeSet,defStyleAttr);
        Log.v("MyView","构造函数3 被调用");
        init();
    }

    //实现绘制的方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取控件的宽高
        int width = getWidth();
        int height = getHeight();
        //设置半径
        int raius = Math.min(width,height)/2;
        //画线
        canvas.drawLine(10,10,100,100,mPaint);
        //画圆
        canvas.drawCircle(width/2,height/2,raidus,mPaint);
        canvas.drawCircle(100,100,20,mPaint);
        Log.v("MyView","onDraw() 被调用");
    }
    //初始化画笔相关设置
    public void init()
    {
        //抗锯齿
        mPaint.setAntiAlias(true);
        //画笔宽度
        mPaint.setStrokeWidth(2f);
        //画笔颜色
        mPaint.setColor(Color.WHITE);
        //画笔填充类型
        mPaint.setStyle(Paint.Style.STROKE);
        Log.v("MyView","init() 被调用,画笔初始化成功");
    }
}

XML布局activity_main.xml部分(使用XML布局中引入的方式引入MyView)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.example.hasee.clockviewdemo.MyView
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#000000"/>
</RelativeLayout>

MainActivity部分

package com.example.hasee.clockviewdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

效果如下:
这里写图片描述

五、相关注意事项

(一)注意三种构造函数的调用情况 ,第一和第二类的构造函数是比较常用的,为了避免出现不必要的与构造函数相关的错误,建议最好把三种构造函数都写上;

(二)注意onDraw()方法在每次绘制的时候都会调用,如果动态绘制的话,onDraw会多次调用,因此建议不要在onDraw()方法中进行画布画笔的相关初始化,通常将这些初始化放到构造函数中,记得三个构造函数都要加上;

(三)注意画笔的颜色与背景的搭配。 曾因为将画笔设置为白色而背景颜色没有设置,即默认为白色,导致自定义VIew没有显示出来,后来花了一个上午的时间尝试断点调试、查看官方文档、日志打印查询等方法来排查问题都还是一无所获,直到我看到了Paint.setColor(Color.White),然后将background设置为 #000000(黑色),发现原来是画笔颜色和背景颜色一样导致的结果(刻骨铭心)

猜你喜欢

转载自blog.csdn.net/Xiongjiayo/article/details/81456313