Android自定义View的使用(基础篇)

前言:
    本文主要讲述自定义View中Paint、Canvas以及Path的使用,不牵扯到PathMeasure和Matrix,提供画一些常见的点、线、面、矩形、圆、椭圆以及不规则图形。
    另外需注意:Android的坐标系和数学中的坐标系是有区别的,Android的坐标系是以屏幕的左上角为坐标原点,垂直向下是Y轴的正方向,切勿和数学坐标系混淆。
    先上图形:

一、自定义View常用方法
    1.构造方法
        自定义View的构造方法有四种,分别是一参二参三参四参,三参四参很少用,主要讲解下一参和二参的区别;
        一参:在code中初始化自定义View的时候调用较多;
        二参:在xml中使用自定义View时会调用;
    2.onDraw:提供画布(Canvas),用来画界面
    3.onMeasure:测量屏幕尺寸,常用方法是getSize和getMode,例(获取屏幕宽度):MeasureSpec.getSize(widthMeasureSpec);
    4.onSizeChanged:在View size发生变化时调用,可以获取old view的size和更新后view的size
    
二、Paint的使用
    1.初始化
        paint = new Paint();
        paint.setColor(Color.RED);//设置颜色
        paint.setStyle(Paint.Style.FILL);//设置paint的类型(包含FILL、STROKE和FILL_AND_STROKE三种)
        paint.setStrokeWidth(10F);//设置线宽
    2.画常见图形
        //点
        canvas.drawPoint(50, 100, paint);
        //一组点
        canvas.drawPoints(new float[]{
                100, 100,
                150, 100,
                200, 100
        }, paint);
        //线
        canvas.drawLine(250, 100, 300, 100, paint);
        //矩形
        canvas.drawRect(new Rect(350, 50, 500, 150), paint);
        //圆角矩形
        canvas.drawRoundRect(new RectF(550, 50, 700, 150), 5, 5, paint);
        //椭圆
        canvas.drawOval(new RectF(750, 50, 900, 150), paint);
        //圆
        canvas.drawCircle(1000, 100, 50, paint);
        //圆弧
        canvas.drawArc(new RectF(1100, 50, 1200, 150), 180, 90, true, paint);
        //空心圆
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(100, 250, 50, paint);
        //饼状图
        paint.setStyle(Paint.Style.FILL);
        RectF rectF = new RectF(250, 200, 350, 300);
        canvas.drawArc(rectF, 0, 60, true, paint);
        paint.setColor(Color.GRAY);
        canvas.drawArc(rectF, 60, 150, true, paint);
        paint.setColor(Color.GREEN);
        canvas.drawArc(rectF, 210, 90, true, paint);
        paint.setColor(Color.YELLOW);
        canvas.drawArc(rectF, 300, 60, true, paint);
        //图片
        //canvas.drawPicture();
        //canvas.drawBitmap();
        //文字
        //canvas.drawText();
    3.实例
        通过以上方法,基本可以满足一些规则图形的需求,例如扇形图表、折线图等,另外也可结合Handler的使用通过invalidate()方法实现动态的效果;
        如下就是简单实现圆柱注水效果的code:
        //画动态水柱
        canvas.drawRoundRect(new RectF(100, 600, 200, 1000), 50, 50, paint);
        paint.setColor(Color.GREEN);
        //下
        canvas.drawArc(new RectF(110, 900, 190, 990), 90 - waterAngle, 2 * waterAngle, false, paint);
        //中
        canvas.drawRect(new RectF(110, waterHeight, 190, 950), paint);
        //上
        if (waterAngle02 == 0) {
            canvas.drawArc(new RectF(110, 610, 190, 700), -waterAngle02, 0, false, paint);
        } else {
            canvas.drawArc(new RectF(110, 610, 190, 700), -waterAngle02, (2 * waterAngle02) + 180, false, paint);
        }

        if (waterAngle < 90) {
            mHandler.sendEmptyMessage(2);//画下半圆
        } else {
            if (waterHeight > 650) {
                mHandler.sendEmptyMessage(1);//画中间
            } else if (waterAngle02 < 90) {
                Log.e("MyView", "waterAngle02:" + waterAngle02);
                mHandler.sendEmptyMessage(3);//画上半圆
            }
        }
        
        //动态水柱
        private float waterAngle = 0;
        private float waterAngle02 = 0;
        private int waterHeight = 950;
        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 1) {
                    if (waterHeight > 645) {
                        waterHeight--;
                        mHandler.sendEmptyMessageDelayed(1, 2000);
                        invalidate();
                    }
                } else if (msg.what == 2) {
                    if (waterAngle < 90) {
                        waterAngle++;
                        mHandler.sendEmptyMessageDelayed(2, 2000);
                        invalidate();
                    }
                } else if (msg.what == 3) {
                    if (waterAngle02 < 90) {
                        waterAngle02++;
                        mHandler.sendEmptyMessageDelayed(2, 2000);
                        invalidate();
                    }
                }
            }
        };

三、Canvas的使用
    画布的使用主要为了更加快捷的确定坐标系的位置,类比我们现实中的画板,如果你想画出来一个倒在地上的金字塔,不如在作画前先将画板向右旋转90度,然后画一个正常的金字塔,完成作品后,再将画纸向左旋转回来,就能达到想要的效果。以下介绍几种画布常见的操作方法:
    1.平移:canvas.translate(150, 0);//将画布向右平移150
    2.旋转:canvas.rotate(30, 100, 100);//将画布围绕点(100, 100)旋转30度
    3.缩放:canvas.scale(2f, 2f, 100, 100);//将画布以点(100, 100)放大两倍
    
四、Path的使用
    canvas除了有draw点draw线draw矩形等方法,还可以drawPath(Path path, Paint paint);
    虽然都是要paint来画,但是drawPath不同的是可以画很多不规则图形,形状取决于path;
    1.首先path也可以画规则图形,方法基本类似canvas中画基本图形的方法
    2.特别介绍path中不同于canvas画基本图形的几个方法
        path.lineTo():在路径上添加一个点
        path.moveTo():移动到下次lineTo的起点
        path.setLastPoint():设置上次操作的最后一个点的位置
        path.close():封闭路径
        path.quadTo():用来画贝塞尔曲线(大部分复杂的自定义View都会用到贝塞尔曲线)
    3.简单的贝塞尔曲线的使用
        为了实现根据touch点来绘制指定的贝塞尔曲线:
    public class BezierView extends View {

    private Paint mPaint;
    private int centerX, centerY;
    private PointF start, end, control;

    public BezierView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setColor(Color.BLUE);
        mPaint.setStyle(Paint.Style.STROKE);

        start = new PointF(0, 0);
        end = new PointF(0, 0);
        control = new PointF(0, 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Path path = new Path();
        path.moveTo(start.x, start.y);
        path.quadTo(control.x, control.y, end.x, end.y);

        canvas.drawPath(path, mPaint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w / 2;
        centerY = h / 2;

        start.x = centerX - 200;
        start.y = centerY;
        end.x = centerX + 200;
        end.y = centerY;
        control.x = centerX;
        control.y = centerY - 100;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        control.x = event.getX();
        control.y = event.getY();
        invalidate();
        return true;
    }
}
        
        

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值