View详解(3)

大家教师节快乐啊,不知道勤学的Coder们有没有去尝试下绘制上篇文章中最后留下的进阶效果,不管怎样,还是一起动手写一遍吧!看看套路是否一致。


水波纹

首先来看图-水波纹中的效果,其具有以下特点:

  • 从内到外四层,内圆外环;
  • 从内到外四个色值;
  • 最内部圆局于View中心;
  • 圆和环同心;

看出以下几点,我们就可以开始按照套路画图了,老套路走起(在以后自定义View部分新建项目及类相关的描述不再赘述)。

声明画笔和宽高

1.声明画笔及宽高 如上分析,我们需要两个画笔,一个用于绘制内圆,一个用于绘制外环。

/**
   * 绘制最中心圆的Paint
   */
  private Paint mInnerCirclePaint;

  /**
   * 绘制外部圆环的Paint
   */
  private Paint mOutterRingPaint;

  /**
   * View宽度
   */
  private int mWidth;

  /**
   * View高度
   */
  private int mHeight;

  /**
   * 外环宽度
   */
  private int mOuttterRingWidth = ;

2.初始化画笔并在构造函数内调用 由于外部为圆环,所以外部画笔样式设置为空心,内部圆画笔样式设置为实心,同时设置画笔宽度为外部圆环宽度。

  public WaveView(Context context) {
    super(context);
    init();
  }

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

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

  private void init() {
    mInnerCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mInnerCirclePaint.setColor(Color.BLUE);
    /** 内部画笔为实心 **/
    mInnerCirclePaint.setStyle(Style.FILL);

    mOutterRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mOutterRingPaint.setColor(Color.BLUE);
    /** 外部画笔为空心 **/
    mOutterRingPaint.setStyle(Style.STROKE);
    mOutterRingPaint.setStrokeWidth(mOuttterRingWidth);
  }

3.初始化宽高

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

计算Points

声明内圆半径,圆环宽度,计算各圆的半径,同心圆及圆环,圆心位于View中心。

如图-水波纹内部距离说明,外环所在圆依次为(radius为外环半径,mInnerRadius为内圆半径,mOutterRingWidth为环宽度):

一环:半径与内圆半径一致,radius = mInnerRadius+(mOutterRingWidth/2)1; 二环:半径等于内圆半径+圆环宽度,radius = mInnerRadius + (mOutterRingWidth/2)3; … 依次类推,我们可以得到外部圆环半径公式:

radius = mInnerRadius + (mOutterRingWidth/2) * i;(i取1,3,5,7,9…)

如此我们就可以开始撸码了。

  /*  声明必要变量 */
  /**
   * 内圆半径
   */
  private int mInnerRadius = ;

  /**
   * 存储计算所得的外环半径
   */
  private int[] mRadius = new int[];
  /* 计算外环半径 */
  private void calculateRadius() {
    for (int i = ; i < ; i++) {
      mRadius[i] = mInnerRadius + (i *  + ) * mOuttterRingWidth / ;
    }
  }

获取画布绘制圆及圆环

重写onDraw函数获取canvas,并绘制圆环及内圆。

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    calculateRadius();
    canvas.drawCircle(mWidth / , mHeight / , mInnerRadius, mInnerCirclePaint);
    for (int i = ; i < ; i++) {
      /** 改变外环的颜色透明度 **/
      mOutterRingPaint.setAlpha( - (int) ( * ((float) (i + ) / )));
      canvas.drawCircle(mWidth / , mHeight / , mRadius[i], mOutterRingPaint);
    }
  }

至于运行效果,大家自己动手试一下喽!


动起来的水波纹

虽然我们画出来了水波纹,但是和蔼的产品还是会批斗你的,他会说,你家水波纹静态的哦?这一秒钟心里是不是有一万只羊驼奔腾?哈哈!奔腾归奔腾,需求我们还是要实现下滴。

那么我们来观察下现实中的水波纹,不难发现与图-水波纹形成 相似的过程。

我们可以看出水波纹动态形成的本质是,外部圆环逐步扩张增加形成的。那么我们只需要动态控制外部圆环的绘制个数,就可以让它动起来了。

属性动画

说到控制外环个数动态增长,做过动画的朋友第一个直觉肯定就是属性动画喽,这样是值变化,所以我们使用ValueAnimator即可(关于属性动画,帧动画,View动画相关的细节,我们在后续文章中单独说明)。

1.声明动画相关的成员

  /**
   * 控制外环个数变化的属性动画对象
   */
  private ValueAnimator mValueAnimator;

  /**
   * 绘制的外环总个数
   */
  private int mOutterRingCount = ;

2.初始化动画对象并开始

public void startAnimation(){
    //创建ValueAnimator对象,按照整型值从0变化到4
    mValueAnimator = ValueAnimator.ofInt(,);
    //设置动画重复类型,RESTART--重新开始,REVERSE--值反转
    mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
    //设置动画重复次数,-1--不限制次数
    mValueAnimator.setRepeatCount(-);
    mValueAnimator.setDuration();
    mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        mOutterRingCount = (int) valueAnimator.getAnimatedValue();
        postInvalidate();
      }
    });
    mValueAnimator.start();
  }

3.更新onDraw循环参数

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    calculateRadius();
    canvas.drawCircle(mWidth / , mHeight / , mInnerRadius, mInnerCirclePaint);
    for (int i = ; i < mOutterRingCount; i++) {
      mOutterRingPaint.setAlpha( - (int) ( * ((float) (i + ) / )));
      canvas.drawCircle(mWidth / , mHeight / , mRadius[i], mOutterRingPaint);
    }
  }

运行效果见gif,至此我们就完成了水波纹自定义View的开发,怎么样?是不是很有趣啊.

本文分享自微信公众号 - 小海编码日记(gh_1f87b8c00ede),作者:小海的编码日记

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-09-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Activity转场动画

    Activity作为Android系统中参与用户交互的重要组件,在日常开发过程中,我们经常需要定义Activity跳转动画以便为用户提供更好的体验,那么怎么设置...

    小海编码日记
  • Android面试题

    (回答任意一个都会追究到源码级,例如说AsyncTask,会问AsyncTask的线程池,并行和串行实现以及BlockingQueue的源码)

    小海编码日记
  • Open GL ES之庖丁解牛

    前文介绍了OpenGL ES绘制图形的基本套路,从上面两篇文章中我们可以看出组成OpenGL ES绘图应用的两个基本元素:

    小海编码日记
  • 【HDU 4940】Destroy Transportation system(无源无汇带上下界可行流)

    Tom is a commander, his task is destroying his enemy’s transportation system. L...

    饶文津
  • 如何提高编程能力?(中)

    函数方程: y - f2 = (f2 - f1) / (x2 - x1)(x - x2) 化简得: x=(f2x1-f1x2)/(f2-f1)

    公众号guangcity
  • 试试这4个CSS动画解决方案和资源

    随着移动设备的大量使用和CSS3兼容性在浏览器中的普及,越来越多的程序猿开始设计和使用基于CSS3的动画效果解决方案,但是自己编写基于CSS3的动画效果也是一件...

    前朝楚水
  • Mysql学习笔记(十一)- Innodb log机制和优化

    在上一片文章中,我们说innodb的内存优化主要是通过多buffer pool size的优化,首先是lru链表的young和old区,以及之间的数据页的迁移的...

    程序员_备忘录
  • C语言程序实践第一周报告(.doc版)

    对于普通类型的求a^n,我们的求法是a*a*a*a....,这样乘以n次,时间复杂度为O(n),对于普通n比较小的我们可以接受,然而当n比较大的时候,计算就慢了...

    glm233
  • 个人认为比较重要的MySQL—innodb参数详解

    innodb_io_capacity:脏页的刷新的数量,可以动态调整,默认是200,该参数的设置取决于硬盘的IOPS的大小,IOPS就是每秒的读写次数。

    小俊丶Eternally
  • 值得关注的5个Python开源项目

    Python领域优秀的开源软件层出不穷。关注一个好的开源软件,对一个开发者来说可以带来很多益处。或者你可以很好地运用这个开源软件,成为它的一个用户;或者你可以阅...

    企鹅号小编

扫码关注云+社区

领取腾讯云代金券