欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-11-27 12:50:28
目标:自定义一个带文字带进度的控件,具体内容如下 效果图: 不啰嗦先看东西: 步骤分析 提取自定义属性 //提供对外暴露的属性,如有不够自己扩...

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

效果图:

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

不啰嗦先看东西:

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就更好了谢谢!

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