最近在做项目的时候,有个功能是订单流程每个阶段的时间段,这个和购物或者外卖的时候的下单、接单、配送类似!请看下图
刚开始的做的时候,没有想过自定义还是按照之前的想法,ui作图根据状态替换图片之类的,后面做着做着感觉好烦,而且这个为了以后方便人调用之类的,所以开始自定义封装!
分析:
1:总共有五个状态,已支付、已接单、等待配送、已签收、待评价
这五个点根据屏幕五等分,每个圆心按照比例相加画大空心圆和小的实心圆。
2:画实线和虚线,根据五等分的比例算出每两个相邻的圆之间的x
长度,左右两边分别加2和减2(留出缝隙处理),这样就可以画出
实线和虚线(实线和虚线根据数据来处理)虚线处理稍微复杂一点,见代码注解
3:现在画时间和状态,这里需要居中处理,刚开始的没有处理,导致字体和圆心没有垂直居中!具体的处理的方法代码有明确说明
给出自定义类:
package org.yidont.ylife.send.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import org.yidont.ylife.send.R;
import org.yidont.ylife.send.bean.OrderStatusDescribeInfo;
import java.util.ArrayList;
import java.util.List;
/**
* Created by li4236 on 16/6/21.
* li4236@aliyun.com
*/
public class CustomRoundTrue extends View {
private final Paint paint;
private final Context context;
public CustomRoundTrue(Context context) {
// TODO Auto-generated constructor stub
this(context, null);
}
public CustomRoundTrue(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
this.paint = new Paint();
this.paint.setAntiAlias(true); //消除锯齿
this.paint.setStyle(Paint.Style.FILL); //绘制空心圆
}
// int number = 5;
int radius = 30;//圆的半径
int vivio = 4;//控制显示多少个实心圆
// int state = 2;//控制底部文字显示
float mFloat[];
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//平分控件的高度,每段的高度
radius = dip2px(15);
int height =getHeight() / 2;
//平分宽度十等分
int width = getWidth() / (5 * 2);
//画虚线的设置start///
int cc = 2 * width - 2 * radius - 4;//计算虚线或者实线的宽度 ,-4是因为左右两边圆各自留出2的距离 查看99和100行
mFloat = new float[cc / 2];
for (int i = 0; i < cc / 2; i++) {
mFloat[i] = 3;//虚线的宽度初始化
}
//画虚线的大小end///
//1 画最上层的圆///start//
int circleY = height - radius - radius / 2;
for (int i = 0; i < mornal.size(); i++) {
OrderStatusDescribeInfo info = mornal.get(i);
int circleX = width + i * 2 * width;
this.paint.setARGB(255, 153, 153, 153);
this.paint.setStrokeWidth(2);
if (info.getStatus().equals("0")) { //画虚圆
canvas.drawCircle(circleX, circleY, radius, this.paint);
} else { //画实圆
drawReal(circleX, circleY, canvas);
}
}
boolean really = false;
for (int j = 0; j < mornal.size()-1; j++) { //画线
really = true;
int n = j+1;
if (n < mornal.size())
{
OrderStatusDescribeInfo info1 = mornal.get(n);
if (info1.getStatus().equals("0"))//获取下一个数据是空的
really = false;
}
int lineX = width + j * 2 * width + radius + 2; //+2是为了留出缝隙
int lineX1 = (width + j * 2 * width) + 2 * width - radius - 2;//-2是为了留出缝隙
if (!really) { //画虚线
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.DKGRAY);
Path path = new Path();
path.moveTo(lineX, circleY);//起点 x/y
path.lineTo(lineX1, circleY);//终点 x/y
PathEffect effects = new DashPathEffect(mFloat, 1);//虚线数组
paint.setPathEffect(effects);
canvas.drawPath(path, paint);
} else {//画实线
this.paint.setARGB(255, 255, 108, 0);
canvas.drawLine(lineX, circleY, lineX1, circleY, paint);
}
}
//1 画最上层的圆///end//
//2 画最下层的文字///start//
int txtY = height + radius;//第一行文字的Y高度
Paint mPaintLines = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintLines.setStrokeWidth(3);
mPaintLines.setTextSize(dip2px(14));
mPaintLines.setTextAlign(Paint.Align.LEFT);
Rect rect = new Rect();
for (int i = 0; i < mornal.size(); i++) {
OrderStatusDescribeInfo info = mornal.get(i);
int lineX = width + i * 2 * width;//每个字符串x坐标
mPaintLines.getTextBounds(info.getText(), 0, 1, rect);//可以获取字体宽高
float awayY2 = txtY + rect.height() + radius / 2;//底层文字y高度计算
if (info.getStatus().equals("1")) {//需要显示的时间和文字
//画时间
mPaintLines.setColor(getResources().getColor(R.color.send_time));
mPaintLines.getTextBounds(info.getTime(), 0, info.getTime().length(), rect);
canvas.drawText(info.getTime(), lineX - rect.width() / 2, txtY, mPaintLines);
//画送货的状态
mPaintLines.setColor(getResources().getColor(R.color.send_state));
mPaintLines.getTextBounds(info.getText(), 0, info.getText().length(), rect);
canvas.drawText(info.getText(), lineX - rect.width() / 2, awayY2, mPaintLines);
} else {
//单个送货的状态
mPaintLines.setColor(getResources().getColor(R.color.send_state_gray));
mPaintLines.getTextBounds(info.getText(), 0, info.getText().length(), rect);
canvas.drawText(info.getText(), lineX - rect.width() / 2, awayY2, mPaintLines);
// //单个送货的状态 ======= 居中显示
// mPaintLines.setColor(getResources().getColor(R.color.send_state_gray));
// mPaintLines.getTextBounds(info.getText(), 0, info.getText().length(), rect);
//
// float awayY = awayY2 / 2 + height / 2 + rect.height() / 2;//设置字体垂直居中计算高度
// canvas.drawText(info.getText(), lineX - rect.width() / 2, awayY, mPaintLines);
}
}
//2 画最下层的文字///end//
super.onDraw(canvas);
}
public void drawReal(int x, int y, Canvas canvas) {
// 绘制外圆
this.paint.setARGB(255, 255, 108, 0);
this.paint.setStrokeWidth(2);
canvas.drawCircle(x, y, radius, this.paint);
//绘制圆环
this.paint.setColor(Color.WHITE);
// this.paint.setStrokeWidth(ringWidth);
canvas.drawCircle(x, y, radius - 3, this.paint);
//绘制内圆
this.paint.setARGB(255, 255, 108, 0);
this.paint.setStrokeWidth(2);
canvas.drawCircle(x, y, radius / 3, this.paint);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public int dip2px( float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public List<OrderStatusDescribeInfo> mornal = new ArrayList<>();
public void setMornal(List<OrderStatusDescribeInfo> mornal) {
this.mornal = mornal;
vivio = mornal.size();//控制显示多少个实心圆
invalidate();
}
}
实体类:
package org.yidont.ylife.send.bean;
/**
* Created by li4236 on 16/7/28.
* li4236@aliyun.com
*/
public class OrderStatusDescribeInfo {
private String status;
private String time;
private String text;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
布局使用:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/yidont_gray"
android:orientation="vertical">
<org.yidont.ylife.send.view.CustomRoundTrue
android:id="@+id/send_round"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/yidont_white"/>
</LinearLayout>
使用方法:
CustomRoundTrue mRoundTrue = (CustomRoundTrue) findViewById(R.id.send_round);
List<OrderStatusDescribeInfo> mornal = new ArrayList<>();
mRoundTrue.setMornal(mornal);
实际项目效果图
如果有问题,欢迎指正!Android开发小白