自定义View详解(2)

首先纠正下上篇的一个描述性错误,对于invalidatepostInvalidate的区别:

  • invalidate:在主线程内部更新时使用;

  • postInvalidate:在非UI线程更新时使用,postInvalidate会把更新要求回传至ViewRootImpl中进行响应;

延续上文内容,进一步针对View的基本概念做详细介绍,接下来我们将学习编写自己的第一个自定义View,一起开始吧!


相信大家在实际生活中都或多或少的画过一些东西,那么我们画一个圆需要做什么准备工作呢?

  • 圆的呈现体:一张纸或地面的一片区域等等,用于圆的展示;

  • 绘制圆的工具:铅笔,圆珠笔,钢笔等等,用于绘制圆;

  • 圆的圆心及半径:确定圆绘制在哪儿,绘制多大;

同样的,在自定义View的开发过程中,我们也需要相似的东西(随后文章中简称为绘制类型自定义View的三要素):

  • Canvas:画布,用于绘制View所要显示的内容,一般来自onDraw()函数的传入,onDraw()函数原型如代码片段-onDraw()所示;

  • Paint :画笔,用于绘制View所需要绘制的内容,相当于笔,在其内部可以设置颜色,粗细,是否实心等信息,一般通过new的方式获取该类对象;

  • Point:点,用于确定View所需要绘制的内容大小及位置等相关信息,当然这里的Point不具有实际意义,也有可能是线段,矩形等,只不过大多数是通过点的组合关系确定而已;

/** onDraw() **/
protected void onDraw(Canvas canvas) {
}

获取宽高

上面我们已经简单了解到View三要素的前两个要素的获取方式,那么点又该如何得到呢?相信细心的朋友要吐槽我了,上一篇不就说过了么?左上角是坐标原点,向下Y正向,向右X正向,就是这么简单。

那么对于一些关键点呢?例如说View的中心,小伙伴们估计又要心急了,有啥好说的,View#getWidth()/2,View#getHeight()/2

但是真的可以做到么?答案是必须等到View走完onMeasure流程后再使用这种方式,否则数据不准确。那么有什么办法呢?

好,大招来了,上篇中刚讲过View的Topleftrightbottom,仔细看图,监听这四个值是不是可以得到View的宽高,很显然可行。系统已经将这一块帮我们做好了,在setLeft(),setRight(),setTop(),setBottom()中均调用了onSizeChanged方法,所以我们只需重写onSizeChanged就可以获得View的宽高了,详情见代码片段-setTop(),同事我们可以看到系统中计算View的宽高方式。

width = right - left
height = bottom - top

/** setTop **/
 public final void stTop(int top) {
        if (top != mTop) {
            ....
            //获取View宽度
            int width = mRight - mLeft;
            int oldHeight = mBottom - mTop;

            mTop = top;
            mRenderNode.setTop(mTop);

            //sizeChange内部调用了onSizeChanged
            sizeChange(width, mBottom - mTop, width, oldHeight);
            ....
        }
    }

  private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 
        //调用onSizeChanged
        onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
        ....
        rebuildOutline();
    }

这里要注意一点,宽高只是限制了显示区域(如上文View边界图所示),和画布大小无关,在View内部绘制区域理论是说是无限大的。


第一个自定义View

知道了如何获取View的宽高,接下来我们就可以开始一次简单的绘制了(在View最中心绘制一个半径200的圆):
打开Android Studio,新建Android Studio,在其内创建Java class 并使其继承自View,重写View的构造方法,代码如片段-Constructor:

/* Constructor */
public class PaintView extends View {
  public PaintView(Context context) {
    super(context);
  }

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

  public PaintView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    }
}

声明画笔和宽高

1.在该类中添加片段-Paint Point中的成员属性:

 /* Paint Point */
 /*
  画笔,用于View内部内容的绘制
   */
  private Paint mPaint;

  /*
  用于存储View的宽高
   */
  private int mWidth,mHeight;

2.初始化宽高,重写onSizeChanged方法,代码如片段-onSizeChanged:

/* onSizeChanged */
 @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    if (w > 0 && h > 0){
      mWidth = w;
      mHeight = h;
    }
  }

3.初始化画笔,并为画笔设置颜色,实心等属性,代码如片段-Paint init:

  /* Paint init */
  //在View构造函数中调用
  private void init(){
    //新建画笔对象
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    //为画笔设置颜色
    mPaint.setColor(Color.BLUE);
    //设置画笔实心空心,Style.FILL--实心,Style.STROKE--空心
    mPaint.setStyle(Style.FILL);
  }

获取画布绘制圆

如上文所述,重写View#onDraw方法获取画布,并绘制圆,代码如片段-onDraw Method:

/* onDraw Method */
/**
* 前两个参数分别代表圆心的X坐标和Y坐标
* 第三个参数是圆半径
* 第四个参数是绘制圆所使用的画笔
*/
canvas.drawCircle(mWidth/2,mHeight/2,200,mPaint);

这里我们调用了画布的画圆方法,相关参数说明在注释上。

XML中声明使用

在Android体系内部View是通过包名的方式反射生成View对象的(后续View树的生成部分会做详细说明),所以针对自定义View,我们要使用全包名的方式在XML中引用,当然也可以通过new的方式生成,代码如片段-activity_main.xml:

<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="com.example.code.customview.MainActivity">

  <com.example.code.customview.PaintView
    android:id="@+id/four_arc_view"
    android:layout_width="400dp"
    android:layout_height="400dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

好了点击三角运行一下吧,如果你没出错,效果应该是图-结果那样的。

 

举一反三,那么请朋友们尝试下,修改画笔颜色,修改画笔样式,在界面左上角200,200位置绘制一个空心圆环吧!

精力更多的亲们,现在可以尝试绘制图-水波纹中的效果了,其中

Paint#setStrokeWidth()可用于设置画笔粗细
Paint#getStrokeWidth()可用于获取画笔宽度
Paint#setAlpha()      可用于改变颜色值的透明度,取值在0-255之间

 

 

完成的你们可以在后台秀绘制结果给我哦!

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值