Android自定义View实现BMI指数条
作者:tyktfj0910 发布时间:2021-08-28 18:12:12
标签:Android,View,BMI
最近项目需要,需要做一个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的宽高,关于具体设置,可以参考鸿洋大神的相关说明:
https://www.jb51.net/article/86061.htm
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");
然后就达到了预期的效果,代码有点乱~


猜你喜欢
- import java.util.ArrayList;import java.util.List;public class Test2 {&
- 同一个service调用service本身如果同一个service调用service本身的方法,出现了事务不能控制。解决方案1.在sprin
- 详解Kotlin Android开发中的环境配置在Android Studio上面进行安装插件在Settings ->Plugins
- java Lock接口java.util.concurrent.locks接口Lockpublic interface Loce
- 最近由于编程的需要,对 C# 的类型转换做了一些研究,其内容涉及 C# 的装箱/拆箱/别名、数值类型间相互转换、字符的 ASCII 码和 U
- 本文实例讲述了c#用for语句输出一个三角形的方法。分享给大家供大家参考。具体分析如下:这是一道面试题,要求是这样的:只使用一个for循环输
- 什么是volatile关键字volatile是Java中用于修饰变量的关键字,其可以保证该变量的可见性以及顺序性,但是无法保证原子性。更准确
- 思维导图一、为什么要学习 DialogFragment你还在用 Dialog 吗?你还在经常烦恼于屏幕翻转的时候,Dialog 的各种奇葩情
- OO思想现在已经在软件开发项目中广泛应用,其中最重要的一个特性就是继承,最近偶简单的复习了下在C#中涉及到继承这个特性时,所需要用到的关键字
- Java关于Map的四种取值方式map的主要作用是什么?可以通过创建一个map的实现类 来存放 数据 值 和值的描述 也可以通过描述去取得数
- 若干年前在使用SpringMVC的时候,发现springMVC可以把HttpSession,HttpRequest组件化注入:@Autowi
- 如果是在资源文件里:<resources> <string name="hello">
- 今天Android Studio提示我这个东东。。。为了加快Gradle的构建速度,我点击了“Update”。。。之后工程一片红,全是R文件
- 1.aar包是android studio下打包android工程中src、res、lib后生成的aar文件,aar包导入其他android
- 1.application.yml中添加两个datasourceserver: port: 8080spring: application:
- 这篇文章主要介绍了Spring-boot的debug调试代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 在C语言中一般用typedef来为回调函数定义别名(参数名)。 别名通过宏定义typedef来实现,不是简单的宏替换。可以用作同
- 本文实例讲述了Android判断Activity是否在最上层的方法。分享给大家供大家参考,具体如下:private boolean isTo
- 本文实例讲述了Android开发中4个常用的工具类。分享给大家供大家参考,具体如下:1、土司工具类(Toast管理)/** * Toast统
- 这篇文章主要介绍了Spring MVC4.1服务器端推送实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习