Android自定義View實(shí)現(xiàn)BMI指數(shù)條
最近項(xiàng)目需要,需要做一個(gè)BMI指數(shù)的指示條,先上效果圖:

BMI指數(shù)從18到35,然后上面指示條的顏色會(huì)隨著偏移量的變化而改變,數(shù)字顯示當(dāng)前的BMI指數(shù),下面的BMI標(biāo)準(zhǔn)也是根據(jù)不同數(shù)值的范圍來判斷的??紤]到這個(gè)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.代碼實(shí)現(xiàn):
新建一個(gè)NewBmiView類,并且繼承自view類,然后添加構(gòu)造方法;
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;
// 定義計(jì)算顏色的參數(shù)
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這兩個(gè)方法,通過onMeasure這個(gè)方法獲取到了view的寬高,關(guān)于具體設(shè)置,可以參考鴻洋大神的相關(guān)說明:
http://www.dbjr.com.cn/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);
}
然后重點(diǎn)就是onDraw這個(gè)方法了:
// 畫自定義的漸變條
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));
// 設(shè)置漸變色
// CLAMP重復(fù)最后一個(gè)顏色至最后
// MIRROR重復(fù)著色的圖像水平或垂直方向已鏡像方式填充會(huì)有翻轉(zhuǎn)效果
// REPEAT重復(fù)著色的圖像水平或垂直方向
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對(duì)象。x方向上的圓角半徑。ry:y方向上的圓角半徑。paint:繪制時(shí)所使用的畫筆。
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("標(biāo)準(zhǔn)", (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);
// 設(shè)置顏色
// 通過BMI來RGB計(jì)算顏色
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);
其中需要注意的是,這里小方塊的顏色值我是根據(jù)BMI值大小,算出RGB三原色的漸變值,沒有找到系統(tǒng)自帶渲染漸變條的方法中,提供的顏色值,所以就用這種方法計(jì)算出來,會(huì)有一定得誤差。
然后就是關(guān)于Textview,因?yàn)樽詭捀?,所以在繪制Textview的時(shí)候,需要考慮寬高再繪制。
通過set方法傳遞參數(shù)
public void setBmi(double bmi) {
this.value = bmi;
// 設(shè)置顏色
if (value < 18) {
this.value = 18;
} else if (value > 35) {
this.value = 35;
}
invalidate();
}
public void setBmiText(String bmiText) {
this.bmiText = bmiText;
}
最后就是在activity中應(yīng)用了:
bmiview= (NewBmiView) getView().findViewById(R.id.bmiview);
//將BMI指數(shù)傳遞過去
bmiview.setBmi(35);
bmiview.setBmiText("35.0");
然后就達(dá)到了預(yù)期的效果,代碼有點(diǎn)亂~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
五分了解Android?Progress?Bar進(jìn)度條加載
這篇文章主要為大家介紹了Android?Progress?Bar進(jìn)度條加載的實(shí)現(xiàn)及屬性示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Flutter模仿實(shí)現(xiàn)微信底部導(dǎo)航欄流程詳解
這篇文章主要介紹了Flutter模仿實(shí)現(xiàn)微信底部導(dǎo)航欄流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-05-05
分析CmProcess跨進(jìn)程通信的實(shí)現(xiàn)
CmProcess是Android一個(gè)跨進(jìn)程通信框架,無需進(jìn)行bindService()操作,不用定義Service,也不需要定義aidl。 支持IPC級(jí)的 Callback,并且支持跨進(jìn)程的事件總線,可同步獲取服務(wù),采用面向接口方式進(jìn)行服務(wù)注冊(cè)與調(diào)用,服務(wù)調(diào)用方和使用者完全解耦2021-06-06

