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

所属分类: 软件编程 / Android 阅读数: 56
收藏 0 赞 0 分享

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

效果图:

不啰嗦先看东西:

步骤分析

提取自定义属性

//提供对外暴露的属性,如有不够自己扩展
  <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就更好了谢谢!

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

更多精彩内容其他人还在看

Android网络编程之获取网络上的Json数据实例

这篇文章主要介绍了Android网络编程之获取网络上的Json数据实例,本文用完整的代码实例讲解了在Android中读取网络中Json数据的方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中的windowSoftInputMode属性详解

这篇文章主要介绍了Android中的windowSoftInputMode属性详解,本文对windowSoftInputMode的9个属性做了详细总结,需要的朋友可以参考下
收藏 0 赞 0 分享

Android网络编程之UDP通信模型实例

这篇文章主要介绍了Android网络编程之UDP通信模型实例,本文给出了服务端代码和客户端代码,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中使用ListView实现漂亮的表格效果

这篇文章主要介绍了Android中使用ListView实现漂亮的表格效果,本文用详细的代码实例创建了一个股票行情表格,需要的朋友可以参考下
收藏 0 赞 0 分享

Android中刷新界面的二种方法

这篇文章主要介绍了Android中刷新界面的二种方法,本文使用Handler、postInvalidate两种方法实现界面刷新,需要的朋友可以参考下
收藏 0 赞 0 分享

Android SDK三种更新失败及其解决方法

这篇文章主要介绍了Android SDK三种更新失败及其解决方法,需要的朋友可以参考下
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(一)

Android3.0(API level 11)开始,Android设备不再需要专门的菜单键。随着这种变化,Android app应该取消对传统6项菜单的依赖。取而代之的是提供anction bar来提供基本的用户功能
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(二)

这次将继续上一篇文章没有讲完的Menu的学习,上下文菜单(Context menu)和弹出菜单(Popup menu)
收藏 0 赞 0 分享

Android学习笔记——Menu介绍(三)

今天继续昨天没有讲完的Menu的学习,主要是Popup Menu的学习,需要的朋友可以参考下
收藏 0 赞 0 分享

Android显示网络图片实例

这篇文章主要介绍了Android显示网络图片的方法,以实例形式展示了Android程序显示网络图片的方法,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多