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

Android自定义View实现BMI指数条

程序员文章站 2024-03-02 13:22:40
最近项目需要,需要做一个bmi指数的指示条,先上效果图: bmi指数从18到35,然后上面指示条的颜色会随着偏移量的变化而改变,数字显示当前的bmi指数,下面的...

最近项目需要,需要做一个bmi指数的指示条,先上效果图:

Android自定义View实现BMI指数条

bmi指数从18到35,然后上面指示条的颜色会随着偏移量的变化而改变,数字显示当前的bmi指数,下面的bmi标准也是根据不同数值的范围来判断的。考虑到这个view的特殊性,最后采用的是自定义的view来完成的。

1.页面布局:

 <linearlayout
  android:layout_width="fill_parent"
  android:layout_height="100dp"
  android:layout_marginleft="5dp"
  android:layout_marginright="5dp"
  android:layout_margintop="50dp"
  android:background="@color/white"
  android:orientation="horizontal" >

  <textview
   style="@style/w_wrap_h_wrap"
   android:layout_margintop="@dimen/login_hei"
   android:text="@string/bmi_text"
   android:textcolor="@color/gray"
   android:textsize="@dimen/login_edit_border_margin" />

  <com.jxj.jwotchhelper.view.newbmiview
   android:id="@+id/bmiview"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent" />
 </linearlayout>

左边是bmi文字,右边是自定义的view,没啥说的,下面是view的具体过程:

2.代码实现:
新建一个newbmiview类,并且继承自view类,然后添加构造方法;

public class newbmiview extends view {

 /** 分段颜色 */
 private static final int[] section_colors = { color.rgb(255, 204, 47), color.green,
   color.red };
 /** 画笔 */
 private paint mpaint;
 private paint textpaint;
 private paint drawablepaint;
 private paint drawablebmipaint;
 private paint bmitextpaint;
 private int bmiwidth, mwidth, mheight, widthsum;
 private double value;
 private double i;
 private double bmi;

 private float valuewidth;
 private string bmitext;

 // 定义计算颜色的参数
 private int x, y, z;

 public newbmiview(context context) {

  super(context);
  initviews(context);
 }

 public newbmiview(context context, attributeset attrs) {
  super(context, attrs);
  initviews(context);
 }

 public newbmiview(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  initviews(context);
 }

 private void initviews(context context) {
 }

然后就是重写onmeasure与ondraw这两个方法,通过onmeasure这个方法获取到了view的宽高,关于具体设置,可以参考鸿洋大神的相关说明:


protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
  int widthspecmode = measurespec.getmode(widthmeasurespec);
  int widthspecsize = measurespec.getsize(widthmeasurespec);
  int heightspecmode = measurespec.getmode(heightmeasurespec);
  int heightspecsize = measurespec.getsize(heightmeasurespec);
  if (widthspecmode == measurespec.exactly
    || widthspecmode == measurespec.at_most) {
   widthsum = widthspecsize;
  } else {
   widthsum = 0;
  }
  if (heightspecmode == measurespec.at_most
    || heightspecmode == measurespec.unspecified) {
   mheight = diptopx(15);
  } else {
   mheight = heightspecsize;
  }
  setmeasureddimension(widthsum, mheight);
 }

然后重点就是ondraw这个方法了:

// 画自定义的渐变条
  mpaint = new paint();
  // 去除锯齿
  mpaint.setantialias(true);
  // 自定义圆角的弧度
  int round = mheight / 20;
  // 新建矩形
  rectf rectbg = new rectf(bmiwidth, mheight - (mheight * 1 / 2), mwidth
    + bmiwidth, mheight - (mheight * 2 / 5));
  // 设置渐变色
  // clamp重复最后一个颜色至最后
  // mirror重复着色的图像水平或垂直方向已镜像方式填充会有翻转效果
  // repeat重复着色的图像水平或垂直方向
  lineargradient shader = new lineargradient(bmiwidth, mheight
    - (mheight * 1 / 2), mwidth + bmiwidth, mheight
    - (mheight * 2 / 5), section_colors, null,
    shader.tilemode.mirror);
  mpaint.setshader(shader);
  // rect:rectf对象。x方向上的圆角半径。ry:y方向上的圆角半径。paint:绘制时所使用的画笔。
  canvas.drawroundrect(rectbg, round, round, mpaint);

  // 画下面的小箭头
  drawablepaint = new paint();
  drawablepaint.setantialias(true);
  bitmap arrowbitmap = bitmapfactory.decoderesource(getresources(),
    r.drawable.arrow_up);
  canvas.drawbitmap(arrowbitmap, mwidth * 2 / 17 + bmiwidth, mheight
    - (mheight * 2 / 5) + 5, drawablepaint);
  canvas.drawbitmap(arrowbitmap, mwidth * 7 / 17 + bmiwidth, mheight
    - (mheight * 2 / 5) + 5, drawablepaint);
  canvas.drawbitmap(arrowbitmap, mwidth * 12 / 17 + bmiwidth, mheight
    - (mheight * 2 / 5) + 5, drawablepaint);

  // 画下方的文字
  string text = "偏瘦";
  rect textbounds = new rect();
  textpaint = new paint();
  textpaint.setantialias(true);
  textpaint.setcolor(color.gray);
  textpaint.settextsize(30);
  // 获取字体的高宽
  textpaint.gettextbounds(text, 0, text.length(), textbounds);
  float textwidth = textbounds.width();
  float textheight = textbounds.height();

  canvas.drawtext("偏瘦", (mwidth * 2 / 17) / 2 - textwidth / 2 + bmiwidth,
    mheight * 7 / 10 + textheight / 2 + 10, textpaint);
  canvas.drawtext("标准", (mwidth * 2 / 17) + (mwidth * 5 / 17) / 2
    - textwidth / 2 + bmiwidth, mheight * 7 / 10 + textheight / 2
    + 10, textpaint);
  canvas.drawtext("超重", (mwidth * 7 / 17) + (mwidth * 5 / 17) / 2
    - textwidth / 2 + bmiwidth, mheight * 7 / 10 + textheight / 2
    + 10, textpaint);
  canvas.drawtext("肥胖", (mwidth * 12 / 17) + (mwidth * 5 / 17) / 2
    - textwidth / 2 + bmiwidth, mheight * 7 / 10 + textheight / 2
    + 10, textpaint);

  // 画上方偏移的小方块
  drawablebmipaint = new paint();
  drawablebmipaint.setantialias(true);
  // 设置颜色

  // 通过bmi来rgb计算颜色
  i = (value - 18) * (34 / 17);
  if (i >= 0 && i <= 17) {
   x = (int) ((17 - i) * (255 / 17));
   y = 204;
   z = 47;

  }
  if (i > 17 && i <= 34) {
   x = (int) ((i - 17) * (255 / 17));
   y = (int) ((34 - i) * (255 / 17));
   z = 0;
  }

  drawablebmipaint.setcolor(color.rgb(x, y, z));
  system.out.println("颜色值为" + string.valueof(x) + string.valueof(y)
    + string.valueof(z));

  canvas.drawrect(getvalue(), mheight / 6, getvalue() + bmibitmap.getwidth(),
    bmibitmap.getheight()+mheight / 6, drawablebmipaint);
  system.out.println("偏移量为" + getvalue());
  canvas.drawbitmap(bmibitmap, getvalue(), mheight / 6, drawablepaint);

  // 画上方偏移的小方块里面的文字
  string bmitext = "40.0";
  rect bmitextbounds = new rect();
  bmitextpaint = new paint();
  bmitextpaint.setantialias(true);
  bmitextpaint.settextsize(35);
  bmitextpaint.setcolor(color.white);
  // 获取字体的高宽
  bmitextpaint.gettextbounds(bmitext, 0, bmitext.length(), bmitextbounds);
  canvas.drawtext(bmitext, getvalue() - (bmitextbounds.width() / 2)
    + bmiwidth, mheight / 3 + (bmitextbounds.height() / 3),
    bmitextpaint);

其中需要注意的是,这里小方块的颜色值我是根据bmi值大小,算出rgb三原色的渐变值,没有找到系统自带渲染渐变条的方法中,提供的颜色值,所以就用这种方法计算出来,会有一定得误差。
然后就是关于textview,因为自带宽高,所以在绘制textview的时候,需要考虑宽高再绘制。
通过set方法传递参数

public void setbmi(double bmi) {
  this.value = bmi;
  // 设置颜色
  if (value < 18) {
   this.value = 18;
  } else if (value > 35) {
   this.value = 35;
  }
  invalidate();
 }

 public void setbmitext(string bmitext) {
  this.bmitext = bmitext;
 }

最后就是在activity中应用了:

bmiview= (newbmiview) getview().findviewbyid(r.id.bmiview);
  //将bmi指数传递过去
  bmiview.setbmi(35);
  bmiview.setbmitext("35.0");

然后就达到了预期的效果,代码有点乱~

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