Android自定义View之酷炫圆环(二)

先看下最终的效果
静态:

动态:

一、开始实现
新建一个DoughnutProgress继承View

  public class DoughnutProgress extends View {

  }

先给出一些常量、变量以及公共方法的代码,方便理解后面的代码

private static final int DEFAULT_MIN_WIDTH = 400; //View默认最小宽度
  private static final int RED = 230, GREEN = 85, BLUE = 35; //基础颜色,这里是橙红色
  private static final int MIN_ALPHA = 30; //最小不透明度
  private static final int MAX_ALPHA = 255; //最大不透明度
  private static final float doughnutRaduisPercent = 0.65f; //圆环外圆半径占View最大半径的百分比
  private static final float doughnutWidthPercent = 0.12f; //圆环宽度占View最大半径的百分比
  private static final float MIDDLE_WAVE_RADUIS_PERCENT = 0.9f; //第二个圆出现时,第一个圆的半径百分比
  private static final float WAVE_WIDTH = 5f; //波纹圆环宽度

  //圆环颜色
  private static int[] doughnutColors = new int[]{
      Color.argb(MAX_ALPHA, RED, GREEN, BLUE),
      Color.argb(MIN_ALPHA, RED, GREEN, BLUE),
      Color.argb(MIN_ALPHA, RED, GREEN, BLUE)};

  private Paint paint = new Paint(); //画笔
  private float width; //自定义view的宽度
  private float height; //自定义view的高度
  private float currentAngle = 0f; //当前旋转角度
  private float raduis; //自定义view的最大半径
  private float firstWaveRaduis;
  private float secondWaveRaduis;

  //
  private void resetParams() {
    width = getWidth();
    height = getHeight();
    raduis = Math.min(width, height)/2;
  }

  private void initPaint() {
    paint.reset();
    paint.setAntiAlias(true);
  }

重写onMeasure方法,为什么要重写onMeasure方法可以看我的上一篇文章,点这里

  /**
   * 当布局为wrap_content时设置默认长宽
   *
   * @param widthMeasureSpec
   * @param heightMeasureSpec
   */
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(measure(widthMeasureSpec), measure(heightMeasureSpec));
  }

  private int measure(int origin) {
    int result = DEFAULT_MIN_WIDTH;
    int specMode = MeasureSpec.getMode(origin);
    int specSize = MeasureSpec.getSize(origin);
    if (specMode == MeasureSpec.EXACTLY) {
      result = specSize;
    } else {
      if (specMode == MeasureSpec.AT_MOST) {
        result = Math.min(result, specSize);
      }
    }
    return result;
  }

下面就是最重要的重写onDraw方法,大致流程如下
在开始绘制之前,先初始化width、height、raduis, 以及将View的中心作为原点

  resetParams();

  //将画布中心设为原点(0,0), 方便后面计算坐标
  canvas.translate(width / 2, height / 2);

实现静态的渐变圆环
1、画渐变圆环

  float doughnutWidth = raduis * doughnutWidthPercent;//圆环宽度
   //圆环外接矩形
   RectF rectF = new RectF(
   -raduis * doughnutRaduisPercent,
   -raduis * doughnutRaduisPercent,
   raduis * doughnutRaduisPercent,
   raduis * doughnutRaduisPercent);
   initPaint();
   paint.setStrokeWidth(doughnutWidth);
   paint.setStyle(Paint.Style.STROKE);
   paint.setShader(new SweepGradient(0, 0, doughnutColors, null));
   canvas.drawArc(rectF, 0, 360, false, paint);

通过修改doughnutColors可以实现不同的渐变效果
2、画圆环旋转头部的圆

  //画旋转头部圆
   initPaint();
   paint.setStyle(Paint.Style.FILL);
   paint.setColor(Color.argb(MAX_ALPHA, RED, GREEN, BLUE));
   canvas.drawCircle(raduis * doughnutRaduisPercent, 0, doughnutWidth / 2, paint);

此时运行代码得到效果如下图:

我们还可以在绘制圆环之前通过旋转画布得到不同初始状态
    canvas.rotate(-45, 0, 0);

    canvas.rotate(-180, 0, 0);

此时聪明的你应该已经想到怎么让这个圆环旋转起来了吧^_^

对!正如你所想的,就是通过canvas.rotate方法不停地旋转画布(这个“地”是这么用的吧o(╯□╰)o)

让圆环旋转起来
在绘制圆环之前加上下面的代码:

  //转起来
  canvas.rotate(-currentAngle, 0, 0);
  if (currentAngle >= 360f){
    currentAngle = currentAngle - 360f;
  } else{
    currentAngle = currentAngle + 2f;
  }

然后再让一个线程循环刷新就好了

private Thread thread = new Thread(){
  @Override
  public void run() {
    while(true){
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      postInvalidate();
    }
  }
};

试试!转起来了吗O(∩_∩)O~

下面是比较有意思的部分,实现类似水波涟漪的效果
分析水波涟漪效果的实现原理(画了张草图方便理解):

假设淡黄色背景区域为整个View的大小

黑色圆圈为View内的最大圆(半径为R3)

橙色圆环代表渐变圆环

红色圆圈代表圆环的外圆(半径为R1)

紫色圆圈是干啥子的,待会儿再介绍~(半径为R2)

通过观察实现的最终效果,可以发现有个圆的半径从R1逐渐增大R3,不透明度逐渐减小到0。

那是不是这样周而复始就可以实现最终的效果了呢?

没那么简单。。。

仔细观察发现,第二个圆不是等到第一个圆的半径增大到R3才开始出现的,而是在将要消失的时候就出现了,有一段时间是两个圆同时存在的。

那么我们就假设当第一个圆的半径增大到R2,第二个圆开始出现。

开始想象两个圆的循环运行模型~~~

我的方案是:

绘制两个圆,每个圆的半径都从R1增大到R1+2x(R2-R1),不透明度还是从R1到R3的过程中逐渐变为0,也就是当圆的半径大于R3时,不透明度就为0了(不可见了),将第一个圆半径初始值设为R1,第二个圆半径初始值设为R2。这样两个圆半径同时逐渐增大,当半径大于 R1+2x(R2-R1)时又重新回到R1大小继续增大,就实现了类似水波涟漪的效果了。

  //实现类似水波涟漪效果
  initPaint();
  paint.setStyle(Paint.Style.STROKE);
  paint.setStrokeWidth(5);
  secondWaveRaduis = calculateWaveRaduis(secondWaveRaduis);
  firstWaveRaduis = calculateWaveRaduis(secondWaveRaduis + raduis*(MIDDLE_WAVE_RADUIS_PERCENT - doughnutRaduisPercent) - raduis*doughnutWidthPercent/2);
  paint.setColor(Color.argb(calculateWaveAlpha(secondWaveRaduis), RED, GREEN, BLUE));
  canvas.drawCircle(0, 0, secondWaveRaduis, paint); //画第二个圆(初始半径较小的)

  initPaint();
  paint.setStyle(Paint.Style.STROKE);
  paint.setStrokeWidth(5);
  paint.setColor(Color.argb(calculateWaveAlpha(firstWaveRaduis), RED, GREEN, BLUE));
  canvas.drawCircle(0, 0, firstWaveRaduis, paint); //画第一个圆(初始半径较大的)

  /**
   * 计算波纹圆的半径
   * @param waveRaduis
   * @return
   */
  private float calculateWaveRaduis(float waveRaduis){
    if(waveRaduis < raduis*doughnutRaduisPercent + raduis*doughnutWidthPercent/2){
      waveRaduis = raduis*doughnutRaduisPercent + raduis*doughnutWidthPercent/2;
    }
    if(waveRaduis > raduis*MIDDLE_WAVE_RADUIS_PERCENT + raduis*(MIDDLE_WAVE_RADUIS_PERCENT - doughnutRaduisPercent) - raduis*doughnutWidthPercent/2){
      waveRaduis = waveRaduis - (raduis*MIDDLE_WAVE_RADUIS_PERCENT + raduis*(MIDDLE_WAVE_RADUIS_PERCENT - doughnutRaduisPercent) - raduis*doughnutWidthPercent/2) + raduis*doughnutWidthPercent/2 + raduis*doughnutRaduisPercent;
    }
      waveRaduis += 0.6f;
    return waveRaduis;
  }

  /**
   * 根据波纹圆的半径计算不透明度
   * @param waveRaduis
   * @return
   */
  private int calculateWaveAlpha(float waveRaduis){
    float percent = (waveRaduis-raduis*doughnutRaduisPercent-raduis*doughnutWidthPercent/2)/(raduis-raduis*doughnutRaduisPercent-raduis*doughnutWidthPercent/2);
    if(percent >= 1f){
      return 0;
    }else{
      return (int) (MIN_ALPHA*(1f-percent));
    }
  }

以上就是本文的全部内容,希望对大家的学习Android软件编程有所帮助。

(0)

相关推荐

  • Android自定义View实现折线图效果

    下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

  • Android自定义View实现照片裁剪框与照片裁剪功能

    本文所需要实现的就是这样一种有逼格的效果: 右上角加了个图片框,按下确定可以裁剪正方形区域里的图片并显示在右上角. 实现思路: 1:首先需要自定义一个ZoomImageView来显示我们需要的图片,这个View需要让图片能够以合适的位置展现在当前布局的图片展示区域内(合适的位置值的是:如果图片长度大于屏幕,则压缩图片长度至屏幕宽度,高度等比压缩并居中显示,如果图片高度大于屏幕,则压缩图片高度至屏幕高度,长度等比压缩并居中显示.): 2:然后需要实现这个拖动的框框,该框框实现的功能有四点:拖动.扩

  • android自定义进度条渐变色View的实例代码

    最近在公司,项目不是很忙了,偶尔看见一个兄台在CSDN求助,帮忙要一个自定义的渐变色进度条,我当时看了一下进度条,感觉挺漂亮的,就尝试的去自定义view实现了一个,废话不说,先上图吧! 这个自定义的view,完全脱离了android自带的ProgressView,并且没使用一张图片,这样就能更好的降低程序代码上的耦合性! 下面我贴出代码  ,大概讲解一下实现思路吧! 复制代码 代码如下: package com.spring.progressview; import android.conten

  • Android 自定义View的使用介绍

    在项目开发中,可能系统自带的一些widget不能满足我们的需求,这时就需要自定义View. 通过查看系统中的常用widget如Button,TextView,EditText,他们都继承自View,所以我们在继承自定义View的时候也自然的需要继承View.1.首先新建一个类LView继承自View 复制代码 代码如下: public class LView extends View { private Paint paint; public LView(Context context) {  

  • Android自定义View实现带数字的进度条实例代码

    第一步.效果展示 图1.蓝色的进度条 图2.红色的进度条 图3.多条颜色不同的进度条 图4.多条颜色不同的进度条 第二步.自定义ProgressBar实现带数字的进度条 0.项目结构 如上图所示:library项目为自定义的带数字的进度条NumberProgressBar的具体实现,demo项目为示例项目以工程依赖的方式引用library项目,然后使用自定义的带数字的进度条NumberProgressBar来做展示 如上图所示:自定义的带数字的进度条的library项目的结构图 如上图所示:de

  • Android自定义View之酷炫数字圆环

    先看下最终的效果 一.开始实现 新建一个DoughnutView继承View public class DoughnutView extends View { } 先重写onMeasure方法. /** * 当布局为wrap_content时设置默认长宽 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int hei

  • Android自定义view制作绚丽的验证码

    废话不多说了,先给大家展示下自定义view效果图,如果大家觉得还不错的话,请继续往下阅读. 怎么样,这种验证码是不是很常见呢,下面我们就自己动手实现这种效果,自己动手,丰衣足食,哈哈~ 一. 自定义view的步骤 自定义view一直被认为android进阶通向高手的必经之路,其实自定义view好简单,自定义view真正难的是如何绘制出高难度的图形,这需要有好的数学功底(后悔没有好好学数学了~),因为绘制图形经常要计算坐标点及类似的几何变换等等.自定义view通常只需要以下几个步骤: 写一个类继承

  • Android自定义View实现广告信息上下滚动效果

    先看看效果: 实现代码: public class ScrollBanner extends LinearLayout { private TextView mBannerTV1; private TextView mBannerTV2; private Handler handler; private boolean isShow; private int startY1, endY1, startY2, endY2; private Runnable runnable; private Li

  • Android中自定义View的实现方式总结大全

    Android自定义view是什么 在我们的日常开发中,很多时候系统提供的view是无法满足我们的需求的,例如,我们想给一个edittext加上清除按钮,等等. 这时候我们就需要对系统的view进行扩展或者组合,这就是所谓的自定义view. Android自定义view的种类 自定义view大概可以分为四个大类,主要是通过实现方式来区分 1.自绘控件,继承view,重写onDraw方法,在其中进行绘制,需要自己适配边距等等 2.继承ViewGroup派生的特殊Layout,主要用于实现自定义布局

  • Android自定义View实现竖直跑马灯效果案例解析

    首先给出跑马灯效果图 中间的色块是因为视频转成GIF造成的失真,自动忽略哈. 大家知道,横向的跑马灯android自带的TextView就可以实现,详情请百度[Android跑马灯效果].但是竖直的跑马灯效果原生Android是不支持的.网上也有很多网友实现了自定义的效果,但是我一贯是不喜欢看别人的代码,所以这篇博客的思路完全是我自己的想法哈. 首先,我们需要给自定义的控件梳理一下格局,如下图所示: 1.首先我们将控件分为三个区块,上面绿色部分为消失不可见的块,中间黑色部分为可见区域,下面红色部

随机推荐