自定义view

1 简介

当Android系统内置的View无法实现我们的需求,需要针对业务定制我们想要的View。自定义view分为两种:自定义view和定义viewgroup。
自定义View需重写三个函数:onMeasure()、onLayout()、onDraw()。

  • onMeasure
    onMeasure(int widthMeasureSpec, int heightMeasureSpec)是View让其父节点知道它想要多大的尺寸。方法的参数widthMeasureSpec和heightMeasureSpec代表 测量模式和宽高的大小。它本身是一个32位的数据,前两位代表模式,后30位代表尺寸大小。如何获取。参考附件代码:
   int widthMode = MeasureSpec.getMode(widthMeasureSpec);
   int widthSize = MeasureSpec.getSize(widthMeasureSpec);

onMeasure包含了3种测量模式:UNSPECIFIED,EXACTLY,AT_MOST。
1. EXACTLY:父view已经强制设置了子view的大小,一般是MATCH_PARENT和固定值
2. UNSPECIFIED:父view对子view没有任何限制,子view可以是任何大小
3. AT_MOST:子view限制在一个最大范围内,一般是WARP_CONTENT-包裹内容

  • onLayout ()
    onLayout 让Android知道View在其父控件中的位置,即距父控件四边的距离left、right、top、bottom。布局是绘图的基础,只有完成了布局,才能对View进行绘图。
  • onDraw()
    onDraw()绘图的前提是已经对View进行了量算和布局,View通过调用draw()方法进行绘图,绘图的目的就是让View在UI界面上呈现出来。

2 onMeasure

首页自定义一个viewgroup 一个button

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.example.test.SelftLayout

        android:background="@color/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.example.test.MyButton
            android:id="@+id/result"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/colorAccent"
            android:text="Hello World!"
            />
    </com.example.test.SelftLayout>
</LinearLayout>

案例—通过改变自定义layout的宽高模式,获取到的数据不同

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);


    final int mode = MeasureSpec.getMode(widthMeasureSpec);
    final int size = MeasureSpec.getSize(widthMeasureSpec);


    switch (mode) {
        case MeasureSpec.AT_MOST:
            Log.d(TAG, "onMeasure: AT_MOST=" );
            break;
        case MeasureSpec.EXACTLY:
            Log.d(TAG, "onMeasure: EXACTLY=" );
            break;
        case MeasureSpec.UNSPECIFIED:
            Log.d(TAG, "onMeasure: UNSPECIFIED=" );
            break;
    }
    int width = SystemUtil.dp2px(getContext(),200);


    setMeasuredDimension(width,width);
    Log.d(TAG, "onMeasure: AT_MOST=" +size+"---width="+getWidth()+"---height="+getHeight());
}

3.onLayout

     @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        final int childCount = getChildCount();

        int left = 0,top = 0,right = 0,bottom = 0;

        for (int x=0;x<childCount;x++){

            final View childAt = getChildAt(x);

            final int measuredWidth = childAt.getMeasuredWidth();
            final int measuredHeight = childAt.getMeasuredHeight();
//            计算距离屏幕左边距离(getLeft())
            left = (getWidth()-measuredWidth)/2;
//            计算距离屏幕顶部距离(getTop())
            top = (getHeight()-measuredHeight)/2;
            // 计算子元素右边缘 距离左边屏幕距离(getRight())
            right = getWidth()-left;
//            计算顶部边缘距离顶部距离
            bottom = top+measuredHeight;

            Log.d(TAG, "onLayout: "+left+"--"+top+"--");
//            布局
            childAt.layout(left,top,right,bottom);
        }

    }

4 onDraw

绘制的意思,绘制的内容,形状。

4.1 Canvas 画布

Canvas我们可以称之为画布,能够在上面绘制各种东西,是安卓平台2D图形绘制的基础,非常强大。

4.2 常用api

操作类型相关API备注
绘制颜色drawColor, drawRGB, drawARGB使用单一颜色填充整个画布
绘制基本形状drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
绘制图片drawBitmap, drawPicture绘制位图和图片
绘制文本drawText, drawPosText, drawTextOnPath依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
绘制路径drawPath绘制路径,绘制贝塞尔曲线时也需要用到该函数
顶点操作drawVertices, drawBitmapMesh通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
画布剪裁clipPath, clipRect设置画布的显示区域
画布快照save, restore, saveLayerXxx, restoreToCount, getSaveCount依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
画布变换translate, scale, rotate, skew依次为 位移、缩放、 旋转、错切
Matrix(矩阵)getMatrix, setMatrix, concat实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。

4.3 使用

4.3.1 绘制点

	@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 	     //创建画笔
        paint = new Paint();
        // 画笔为填充模式
        paint.setStyle(Paint.Style.FILL);
        //画笔颜色
        paint.setColor(Color.RED);
        // 画笔宽度
        paint.setStrokeWidth(11f);

		canvas.drawPoint(300,300, paint);

4.3.2 绘制线

	@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 	     //创建画笔
 	     
        paint = new Paint();
        // 画笔为填充模式  STROKE //描边   FILL //填充   FILL_AND_STROKE //描边加填充
        paint.setStyle(Paint.Style.FILL);
        //画笔颜色
        paint.setColor(Color.RED);
        // 画笔宽度
        paint.setStrokeWidth(11f);

	  canvas.drawLine(300,300,500,600,paint);

4.3.3 绘制矩形

确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。

// 第一种
canvas.drawRect(100,100,800,400,mPaint);

// 第二种
Rect rect = new Rect(100,100,800,400);
canvas.drawRect(rect,mPaint);

// 第三种
RectF rectF = new RectF(100,100,800,400);
canvas.drawRect(rectF,mPaint);

4.3.4 绘制圆

canvas.drawCircle(500,500,400,mPaint); // 绘制一个圆心坐标在(500,500),半径为400 的圆。

4.3.5 绘制圆角矩形

// 第一种
RectF rectF = new RectF(100,100,800,400);
canvas.drawRoundRect(rectF,30,30,mPaint);

// 第二种
canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值