Android自定义View直线比例图
nsih8320
8年前
<p>项目中用到下面的效果:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/fdedc0f77b95bde128e9c646018e561c.png"></p> <p>总共有四种状态,分四种颜色,根据传入的每种状态的比例值在直线上显示各自的长度。</p> <p>这种效果最终用两种方法完成。</p> <h3><strong>第一种</strong></h3> <p>第一种方法是首先想到的一种方法,自定义一个FrameLayout,在里面有四个互相重叠的Imageview或者textview。背景使用shpe绘制四个圆角矩形。然后根据传入的值动态改变imageview或者textview的宽度</p> <p>shape:</p> <pre> <code class="language-java"><?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 圆角 --> <corners android:radius="10dp" /> <solid android:color="@color/patrol_no_start_gray"/> </shape></code></pre> <p>view:</p> <pre> <code class="language-java">package com.chs.listtext; import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextView; /** * 作者:chs on 2016/9/27 14:02 * 邮箱:657083984@qq.com */ public class ProgressScaleView extends FrameLayout { private int[] resId = new int[]{R.drawable.shape_patrol_corners_gray, R.drawable.shape_patrol_corners_red, R.drawable.shape_patrol_corners_yellow, R.drawable.shape_patrol_corners_blue}; private double [] scales = new double[4]; private int mWidth; public ProgressScaleView(Context context) { super(context); init(context); } public ProgressScaleView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ProgressScaleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public void setScales(double[] scales) { this.scales = scales; invalidate(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); int count = getChildCount(); //依次改变textview的宽度 for (int i = 0; i < count; i++) { TextView view = (TextView) getChildAt(i); float scale = 0; for(int j = 0;j<scales.length-i;j++){ scale+=scales[j]; } view.getLayoutParams().width = (int) (mWidth*scale); } } private void init(Context context) { mWidth = context.getResources().getDisplayMetrics().widthPixels-DensityUtil.dip2px(context, 40); //创建四个textview 宽度都为ViewGroup.LayoutParams.MATCH_PARENT 依次覆盖 for (int i = 0; i < 4; i++) { TextView textView = new TextView(context); textView.setHeight(DensityUtil.dip2px(context, 20)); textView.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); textView.setBackgroundResource(resId[i]); addView(textView); } } }</code></pre> <h3><strong>第二种</strong></h3> <p>第一种还是有点麻烦,得写四种shape 创建textview对象。其实想一想这个效果直接在view上绘制小圆角矩形不就行了,于是有了第二种:</p> <pre> <code class="language-java">package com.hsm.bxt.widgets; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import com.hsm.bxt.utils.DensityUtil; /** * 作者:chs on 2016/9/28 10:03 * 邮箱:657083984@qq.com */ public class ScaleView extends View { private int mWidth; private RectF mRect1; private RectF mRect2; private RectF mRect3; private RectF mRect4; private Paint mPaint; private int [] mColors = new int[]{Color.parseColor("#C4D4E8"),Color.parseColor("#FF727A"),Color.parseColor("#FFC636"),Color.parseColor("#44B2FE")}; private static final int BG_COLOR = Color.parseColor("#FFFFFF"); public ScaleView(Context context) { super(context); init(context); } public ScaleView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { setWillNotDraw(false); int height = DensityUtil.dip2px(context, 10); mWidth = context.getResources().getDisplayMetrics().widthPixels-DensityUtil.dip2px(context, 40); mRect1 = new RectF(0,0,0, height); mRect2 = new RectF(0,0,0, height); mRect3 = new RectF(0,0,0, height); mRect4 = new RectF(0,0,0, height); mPaint = new Paint(); mPaint.setAntiAlias(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); // super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mWidth = w; super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(BG_COLOR); mPaint.setColor(mColors[0]); canvas.drawRoundRect(mRect1,15,15,mPaint); mPaint.setColor(mColors[1]); canvas.drawRoundRect(mRect2,15,15,mPaint); mPaint.setColor(mColors[2]); canvas.drawRoundRect(mRect3,15,15,mPaint); mPaint.setColor(mColors[3]); canvas.drawRoundRect(mRect4,15,15,mPaint); } /** * 给数据赋值 * @param scales */ public void setScales(double[] scales){ float scale1 = 0; for (int j = 0; j < scales.length - 0; j++) { scale1 += scales[j]; } mRect1.right = (int) (mWidth*scale1); float scale2 = 0; for (int j = 0; j < scales.length - 1; j++) { scale2 += scales[j]; } mRect2.right = (int) (mWidth*scale2); float scale3 = 0; for (int j = 0; j < scales.length - 2; j++) { scale3 += scales[j]; } mRect3.right = (int) (mWidth*scale3); float scale4 = 0; for (int j = 0; j < scales.length - 3; j++) { scale4 += scales[j]; } mRect4.right = (int) (mWidth*scale4); invalidate(); } }</code></pre> <p>绘制流程:</p> <p>先绘制灰色、红色,黄色、蓝色。一层一层的覆盖。</p> <p>最主要的方法就是setScales() 方法。因为绘制的流程是先绘制最后一个颜色(灰色)其实灰色永远都是绘制百分之百的宽度。红色的宽度就是总宽度乘以(1-灰色比例),黄色宽度是 总宽度乘以(1-灰色比例-红色宽度),蓝色宽度是总宽度乘以它自己的比例或者乘以(1-灰色比例-红色比例-黄色比例)。</p> <p> </p> <p> </p> <p> </p>