一,先上效果图。
二,思路讲解。
①先画出X Y轴 xy的坐标如下
②,画出Y轴的两条等量线(标识线)未消毒,已消毒的横线(比较浅的那两条)。
③,循环画出底部的X轴上的时间,以及折现的开始结束
1)由于折线的长短要根据时间的长短来显示,所以这里通过计算比例,实现了,时间越长,折现越长。反之
④,最后要处理一下长宽*的问题,所以一开始要给好dp/px做好转换,适配。
三,代码详细
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class XyTime1 extends View {
private Context context;
public XyTime1(Context context) {
super(context);
this.context = context;
initView();
}
public XyTime1(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
this.context = context;
}
public XyTime1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
this.context = context;
}
public XyTime1(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
this.context = context;
}
//背景的颜色
public Paint xyPaint = new Paint();
public Paint xyPaint1 = new Paint();
public Paint xPaint = new Paint();
public Paint font = new Paint();
public Paint linfont = new Paint();
public void initView() {
xyPaint.setColor(ContextCompat.getColor(getContext(), R.color.linexy));
xyPaint.setStrokeWidth(3f);
xyPaint.setStrokeCap(Paint.Cap.ROUND);
xyPaint1.setColor(ContextCompat.getColor(getContext(), R.color.white1));
xyPaint1.setStrokeWidth(3f);
xyPaint1.setStrokeCap(Paint.Cap.ROUND);
xPaint.setColor(ContextCompat.getColor(getContext(), R.color.linexy));
xPaint.setStrokeWidth(1f);
font.setTextSize(12f);
font.setColor(ContextCompat.getColor(getContext(), R.color.white));
linfont.setTextSize(20f);
linfont.setStrokeWidth(10f);
linfont.setColor(ContextCompat.getColor(getContext(), R.color.chart));
linfont.setStrokeCap(Paint.Cap.ROUND);
// startX:开始点X坐标
// startY:开始点Y坐标
// stopX:结束点X坐标
// stopY:结束点Y坐标
}
int PointX;
public float left = 0f;
public float right = 1080 + 150f;
public float top = 0f;
public float bottom = 192;//40f
private int def = 1230;
int slideX = 50+PointX;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//X
canvas.drawLine(slideX, 192, def + PointX, 192, xyPaint);
//Y
canvas.drawLine(slideX, 50, slideX, 192, xyPaint1);
Log.d("onDraw:", "" + PointX);
//已消毒 上条
canvas.drawLine(slideX, 192 - 100, def + PointX, 192 - 100, xPaint);
//未消毒下
canvas.drawLine(slideX, 192 - 50, def + PointX, 192 - 50, xPaint);
canvas.drawText("未消毒", slideX-50, 192 - 100 + 10, font);
canvas.drawText("消毒中", slideX-50, 192 - 50 + 10, font);
//底部时间坐标,根据每个坐标 间距30
//初始位置,150
int x = 100 + PointX;
int x1 ;//每次改变后,x1
int nextType = 0;//下一个标记
int a = 0;//当前一个时间
int b = 0;//下一个时间
for (int i = 0; i < names.length; i++) {
x += 120;//x结束位置 //每次的位置 这里要保证x不能小于50,
x1 = x - 120;//x结束的位置 //140 -27
canvas.drawText(names[i], x - 140, 192 + 30, font);
//这里还要增加 当前位置 X Y 线
if (i + 1 < names.length) {
//就取下一个
nextType = imts[i + 1];
//判断一下,长度大于2不然,报错。
a = Integer.parseInt(names[i].substring(0, 2));//当前这个
b = Integer.parseInt(names[i + 1].substring(0, 2));//下一个
//每小时增加15px
x += (b - a) * 15;
} else {
//没有下一个imts[i+1]
nextType = imts[i];
}
setLine(canvas, x, x1, imts[i], nextType);
}
}
private String[] names = {"08:00", "08:00", "11:30", "13:30", "14:00", "15:00", "23:00", "24:00", "24:00"};
private int[] imts = {0, 1, 0, 1, 0, 1, 0, 1, 0};
int statex = 0;
//设置两点之间的线。
private void setLine(Canvas canvas, int x, int x1, int type, int nextType) {
// x
// y
Log.d("c:", "");
if (type == 1) {//开始消毒
canvas.drawLine(x1 + 3, 192 - 100, x, 192 - 100, linfont);
} else {
//未消毒
canvas.drawLine(x1 + 3, 192 - 50, x, 192 - 50, linfont);
}
//2条线之间的Y线
//判断当前这个线 跟下一条线的 也就是 type 是不是一样 ,如果是一样,就不画Y线,
//如果不一样,就是画Y线的时候
if (type != nextType) {
// //画Y线
canvas.drawLine(x, 192 - 50, x, 192 - 100, linfont);
}
}
/**
* 测量宽高。不然 设置大小无用
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int width = 0;
int height = 0;
//获得宽度MODE
int modeW = MeasureSpec.getMode(widthMeasureSpec);
//获得宽度的值
if (modeW == MeasureSpec.AT_MOST) {
width = MeasureSpec.getSize(widthMeasureSpec);
}
if (modeW == MeasureSpec.EXACTLY) {
width = widthMeasureSpec;
}
if (modeW == MeasureSpec.UNSPECIFIED) {
width = 600;
}
//获得高度MODE
int modeH = MeasureSpec.getMode(height);
//获得高度的值
if (modeH == MeasureSpec.AT_MOST) {
height = MeasureSpec.getSize(heightMeasureSpec);
}
if (modeH == MeasureSpec.EXACTLY) {
height = heightMeasureSpec;
}
if (modeH == MeasureSpec.UNSPECIFIED) {
//ScrollView和HorizontalScrollView
height = 240;
}
//设置宽度和高度
setMeasuredDimension(width, height);
}
private int lastX;
private int lastY;
//手指按下的时间长
public long startTime = 0;
int downX;//按下的坐标
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
//按下
case MotionEvent.ACTION_DOWN:
startTime = System.currentTimeMillis();
downX = (int) event.getX();
// invalidate();
break;
//拖动
case MotionEvent.ACTION_MOVE:
// startTime = System.currentTimeMillis();
PointX = (int) event.getX();
Log.d("getRawX:", "" + event.getRawX());
Log.d("getX:", "" + event.getX());
Log.d("getLeft:", "" +getLeft()); //0
Log.d("getRight:", "" + getRight());//1280
Log.d("getTop:", "" + getTop());//0
Log.d("getBottom:", "" + getBottom());//240
// if (downX > PointX) {
// //说明 在忘左边滑动
// PointX = PointX - downX;
//
// }
// if (downX < PointX) {
// if (PointX < 700) {
// PointX = (int) event.getX();
// }
// }
invalidate();
// //右边
// if (PointX>50){
// invalidate();
// }
// }
break;
//抬起
case MotionEvent.ACTION_UP:
PointX = (int) event.getX();
long endTime = System.currentTimeMillis();
if (endTime - startTime > 500) {//如果按下,抬起时间过大才认为是拖动,要执行动画。
}
break;
}
return true;
//这种整体移动
// int action = event.getAction();
// switch (action) {
// case MotionEvent.ACTION_DOWN:
// lastX = (int) event.getRawX();//获取触摸事件触摸位置的原始X坐标
// lastY = (int) event.getRawY();
// break;
// case MotionEvent.ACTION_MOVE:
// //event.getRawX();获得移动的位置
// int dx = (int) event.getRawX() - lastX;
// int dy = (int) event.getRawY() - lastY;
// int l = this.getLeft() + dx;
// int b = this.getBottom() + dy;
// int r = getRight() + dx;
// int t = getTop() + dy;
// this.layout(l, t, r, b);//重新布局
// lastX = (int) event.getRawX();
// lastY = (int) event.getRawY();
// break;
// case MotionEvent.ACTION_UP:
// break;
// }
// return true;//由于要处理所有手势,全部返回true;
}
// @Override
// protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// super.onLayout(changed, left, top, right, bottom);
// this.left = left;
// this.top = top;
// this.right = right;
// this.bottom = bottom;
//
// }
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
四,有需要定制UI的加我Q:1181620038