Android view自定义带文字带进度的控件

目标:自定义一个带文字带进度的控件,具体内容如下

效果图:

不啰嗦先看东西:

步骤分析

提取自定义属性

//提供对外暴露的属性,如有不够自己扩展
  <declare-styleable name="DescProgressView">
    <attr name="dpv_text_normal_color" format="color" />
    <attr name="dpv_text_seleced_color" format="color" />
    <attr name="dpv_text_size" format="dimension" />
    <attr name="dev_progress_bg_color" format="color" />
    <attr name="dev_progress_small_circle_color" format="color" />
    <attr name="dev_progress_big_circle_color" format="color" />
  </declare-styleable>

解析自定义属性

private void initAttrs(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DescProgressView, defStyleAttr, R.style.Def_DescProgressViewStyle);
    int indexCount = typedArray.getIndexCount();
    for (int i = 0; i < indexCount; i++) {
      int attr = typedArray.getIndex(i);
      switch (attr) {
        case R.styleable.DescProgressView_dpv_text_normal_color:
          textNormalColor = typedArray.getColor(attr, Color.BLACK);
          break;
        case R.styleable.DescProgressView_dpv_text_seleced_color:
          textSelectedColor = typedArray.getColor(attr, Color.BLACK);
          break;
        case R.styleable.DescProgressView_dpv_text_size:
          dpvTextSize = typedArray.getDimensionPixelSize(attr, 0);
          break;
        case R.styleable.DescProgressView_dev_progress_bg_color:
          dpvProgressBgColor = typedArray.getColor(attr, Color.BLACK);
          break;
        case R.styleable.DescProgressView_dev_progress_small_circle_color:
          dpvSmallCicleColor = typedArray.getColor(attr, Color.BLACK);
          break;
        case R.styleable.DescProgressView_dev_progress_big_circle_color:
          dpvBigCircleColor = typedArray.getColor(attr, Color.BLACK);
          break;
      }
    }
    typedArray.recycle();
  }

测量UI图的比例(包含图标大小比例,位置比例)

//这里大家可以根据自己的习惯来,我习惯用view的尺寸当做参照,来约束界面的view,各有利弊,也可以暴露出属性设置具体的dp值,根据比例的话,调整好比例后,所有的绘制内容会统一约束
  private static final float SCALE_OF_PROGRESS_HEIGHT = 70.F / 120;
  private static final float SCALE_OF_TOP_AND_BOTTOM_PADDING = 10.F / 120;
  private static final float SCALE_OF_LEFT_AND_RIGHT_PADDING = 20.F / 120;
  private static final float SCALE_OF_TEXT_DESC_CONTAINER = 50.F / 120;
  private static final float SCALE_OF_BIG_CIRCLE_HEIGHT = 22.F / 120;
  private static final float SCALE_OF_SMALL_CIRCLE_HEIGHT = 16.F / 120;
  private static final float SCALE_OF_LINE_HEIGHT = 4.F / 120;
  private static final float DEF_VIEW_HEIGHT = 120.F;

提取绘制的各个元素的位置属性坐标等

这个view的唯一要提前确定的就是文字的位置,文字的位置确定需要知道所有文字的长度,左右间距,计算出中间的白色间隔
代码如下

 /**
   * 获取文字在画布中的位置
   */
  private void getDescTextRegonPoint() {
    for (int i = 0; i < descs.size(); i++) {
      Point textRegonPoint = new Point();
      int sumX = 0;
      //非常重要:计算各个文字在view中的具体坐标,体会下这个二级for循环,子循环是确定每个描述文本的位置
      for (int j = 0; j < i; j++) {
        Point tempSum = allDescTextPoints.get(j);
        sumX += tempSum.x;
      }
      sumX += i * getTextDescSpace();
      textRegonPoint.x = sumX + leftAndRightPadding;
      textRegonPoint.y = dpViewHeight - topAndBottomPadding - textDescContainerHeight / 2;
      textPoints4Draw.add(textRegonPoint);
    }
  }
 /**
   * 获取文字的间距
   *
   * @return 获取文字的间距
   */
  private float getTextDescSpace() {
    float allDescWith = 0;
    for (Point tempDesc : allDescTextPoints) {
      allDescWith += tempDesc.x;
    }
    int textContainerW = (int) (dpViewWidth - leftAndRightPadding * 2 - allDescWith);
    if (descs != null && descs.size() > 1) {
      int spaceCount = descs.size() - 1;
      return textContainerW * 1.F / spaceCount;
    }
    return 0;
  }

绘制

我们在view测量确定了尺寸完毕之后,直接绘制即可

 @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  // 确定各个比例的大小
    super.onSizeChanged(w, h, oldw, oldh);
    dpViewHeight = h;
    dpViewWidth = w;
    progressContainerHeight = (int) (SCALE_OF_PROGRESS_HEIGHT * dpViewHeight);
    topAndBottomPadding = (int) (SCALE_OF_TOP_AND_BOTTOM_PADDING * dpViewHeight);
    leftAndRightPadding = (int) (SCALE_OF_LEFT_AND_RIGHT_PADDING * dpViewHeight);
    textDescContainerHeight = (int) (SCALE_OF_TEXT_DESC_CONTAINER * dpViewHeight);
    smallCircleRadio = (int) (SCALE_OF_SMALL_CIRCLE_HEIGHT * dpViewHeight / 2);
    bigCircleRadio = (int) (SCALE_OF_BIG_CIRCLE_HEIGHT * dpViewHeight / 2);
    lineHeight = (int) (SCALE_OF_LINE_HEIGHT * dpViewHeight);

    // 获取各个部分所需要的约束坐标
    getDescTextWidthAndHeight();
    getDescTextRegonPoint();
    getBgLineRectF();
    getBgCirclePoints();
    getSelectedRectF();
    getColorFullRectF();
    getGrayRectF();
  }
@Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  drawDescText(canvas);
  drawBgLine(canvas);
  drawSelectedLine(canvas);
  drawGrayRectF(canvas);
  drawSelectedCircles(canvas);
 }
//绘制部分的代码就是canvas 的API的使用,没有什么技术含量.
//最后暴露给外面设置数据的接口

public void setProgressDescs(List<String> descs, int currentSelectPosition) {
  this.currentSelectPosition = currentSelectPosition;
  if (descs != null && descs.size() > 1) {
   this.descs.clear();
   this.descs.addAll(descs);
   this.allDescTextPoints.clear();
   invalidate();
  }
 }

源代码下载地址https://github.com/GuoFeilong/DescPbView来个star就更好了谢谢!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义View基础开发之图片加载进度条

    学会了Paint,Canvas的基本用法之后,我们就可以动手开始实践了,先写个简单的图片加载进度条看看. 按照惯例,先看效果图,再决定要不要往下看: 既然看到这里了,应该是想了解这个图片加载进度条了,我们先看具体用法,再看自定义View的实现: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.co

  • Android Webview添加网页加载进度条实例详解

    推荐阅读:Android WebView线性进度条实例详解 最近在android项目中使用webview嵌套了一个抽奖活动网页,活动上线,运行良好(改了N次需求和突发bug),还好这种模式的活动,只需要修改网页,不需要重新打包发布市场,这也是这种模式开发的优势之一.后来据产品哥反馈说加载网页无进度提示,好吧,这个当时真没考虑这么多,这个要加加..想当然以为轻松搞定之....其实还是比轻松要复杂点... 1.首先自定义一个WebView控件 /** * 带进度条的Webivew * @author

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

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

  • Android 自定义view和属性动画实现充电进度条效果

    近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和自定义view的方式来完成这个功能,将它开源出来,供有需要的人了解一下相关的内容. 本次实现的功能类似下面的效果: 接下来便详细解析一下如何完成这个功能,了解其中的原理,这样就能举一反三,实现其他类似的动画效果了. 详细代码请看大屏幕 https://github.com/crazyandcoder

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

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

  • Android view自定义实现动态进度条

    Android  自定义view实现动态进度条 效果图: 这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧.顶部.右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的.比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画

  • Android中实现Webview顶部带进度条的方法

    写这篇文章,做份备忘,简单滴展示一个带进度条的Webview示例,进度条位于Webview上面. 示例图如下: 主Activity代码: 复制代码 代码如下: package com.droidyue.demo.webviewprogressbar; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.vi

  • android ListView和ProgressBar(进度条控件)的使用方法

    ListView控件的使用:ListView控件里面装的是一行一行的数据,一行中可能有多列,选中一行,则该行的几列都被选中,同时可以触发一个事件,这种控件在平时还是用得很多的.使用ListView时主要是要设置一个适配器,适配器主要是用来放置一些数据.使用起来稍微有些复杂,这里用的是android自带的SimpleAdapter,形式如下:android.widget.SimpleAdapter.SimpleAdapter(Context context, List<? extends Map<

  • Android自定义WaveView实现波浪进度效果

    实现原理 首先就是自定义个WaveView 继承View,然后再WaveView 内部实现代码逻辑: ① 水波就波嘛? sin函数? 贝塞尔曲线? 都行,这里就用二阶贝塞 尔曲线去画吧 ② 波要动嘛,怎么动呢?线程? 好吧 这里用了个Handler. ③绘制波首先要找点,那么在onMeasure()里找出需要的点咯,这里就暂时展示一个波段吧,一个波长移动左边不就没了?OK 那就两个波吧,吼吼,两个波(猥琐男潜质表露无遗啊).接下来就是Handler 结合 onDraw()绘制.OK,那就先看我W

  • Android自定义view实现水波纹进度球效果

    今天我们要实现的这个view没有太多交互性的view,所以就继承view. 自定义view的套路,套路很深 1.获取我们自定义属性attrs(可省略) 2.重写onMeasure方法,计算控件的宽和高 3.重写onDraw方法,绘制我们的控件 这么看来,自定义view的套路很清晰嘛. 我们看下今天的效果图,其中一个是放慢的效果(时间调的长) 我们按照套路来. 一.自定义属性 <declare-styleable name="WaveProgressView"> <at

随机推荐