效果目标:
1.现在到未来24小时温度点连成贝塞尔曲线
2.指示器跟随选中每小时空气质量移动
3.合并相同风力与天气icon
4.显示区域的icon在屏幕可视范围内左右居中
5.显示区域的风力等级在屏幕可视范围内左右居中
最终效果:
实现过程:
1.首先绘制贝塞尔曲线
//绘制温度贝塞尔曲线
private void drawCurve(Canvas canvas, List<Point> points) {
Path curvePath = new Path();
//绘制点的 x,y轴 集合
points_x.clear();
points_y.clear();
//遍历 把points的x,y点添加到集合里
for (int i = 0; i < points.size(); i++) {
if (points.get(i) == null) {
break;
}
if (i == points.size() - 1) {
points_x.add(points.get(i).x);
points_x.add(points.get(i).x + ITEM_WIDTH);
points_y.add(points.get(i).y);
} else {
points_x.add(points.get(i).x);
}
points_y.add(points.get(i).y);
}
//把点转换 实现圆润的效果
List<Cubic> calculate_x = calculate(points_x);
List<Cubic> calculate_y = calculate(points_y);
//从 x,y的0点绘制
curvePath.moveTo(calculate_x.get(0).eval(0), calculate_y.get(0).eval(0));
//循环绘制 STEPS越大 绘制的点越密
for (int i = 0; i < calculate_x.size(); i++) {
for (int j = 1; j <= STEPS; j++) {
float u = j / (float) STEPS;
curvePath.lineTo(calculate_x.get(i).eval(u), calculate_y.get(i)
.eval(u));
}
}
canvas.drawPath(curvePath, curveLinePaint);
}
点转换的方法
/**
* 计算 贝塞尔曲线的 点
*
* @param x
* @return
*/
private List<Cubic> calculate(List<Integer> x) {
int n = x.size() - 1;
float[] gamma = new float[n + 1];
float[] delta = new float[n + 1];
float[] D = new float[n + 1];
int i;
gamma[0] = 1.0f / 2.0f;
for (i = 1; i < n; i++) {
gamma[i] = 1 / (4 - gamma[i - 1]);
}
gamma[n] = 1 / (2 - gamma[n - 1]);
delta[0] = 3 * (x.get(1) - x.get(0)) * gamma[0];
for (i = 1; i < n; i++) {
delta[i] = (3 * (x.get(i + 1) - x.get(i - 1)) - delta[i - 1])
* gamma[i];
}
delta[n] = (3 * (x.get(n) - x.get(n - 1)) - delta[n - 1]) * gamma[n];
D[n] = delta[n];
for (i = n - 1; i >= 0; i--) {
D[i] = delta[i] - gamma[i] * D[i + 1];
}
/* now compute the coefficients of the cubics */
List<Cubic> cubics = new LinkedList<Cubic>();
for (i = 0; i < n; i++) {
Cubic c = new Cubic(x.get(i), D[i], 3 * (x.get(i + 1) - x.get(i))
- 2 * D[i] - D[i + 1], 2 * (x.get(i) - x.get(i + 1)) + D[i]
+ D[i + 1]);
cubics.add(c);
}
return cubics;
}
然后绘制曲线到底部的背景
/**
* 绘制 曲线下背景和分割线
* <p>
* 1. 先把曲线找到 然后画曲线到右下 右下画左下 左下到 曲线0点
* 2.闭合1画的路径 设置渐变
* 3.把记录需要画分割线的下标遍历绘制
*/
private void onDrawLineBg(Canvas canvas, List<Point> points) {
//背景的path
Path curvePath = new Path();
//分割线的patn
Path linePath = new Path();
points_x.clear();
points_y.clear();
for (int i = 0; i < points.size(); i++) {
if (points.get(i) == null) {
break;
}
if (i == points.size() - 1) {
points_x.add(points.get(i).x);
points_x.add(points.get(i).x + ITEM_WIDTH);
points_y.add(points.get(i).y);
} else {
points_x.add(points.get(i).x);
}
points_y.add(points.get(i).y);
}
List<Cubic> calculate_x = calculate(points_x);
List<Cubic> calculate_y = calculate(points_y);
//从 0 点开始画
curvePath.moveTo(calculate_x.get(0).eval(0), calculate_y.get(0).eval(0));
linePath.moveTo(calculate_x.get(0).eval(0), calculate_y.get(0).eval(0));
//连接贝塞尔曲线
for (int i = 0; i < calculate_x.size(); i++) {
for (int j = 1; j <= STEPS; j++) {
float u = j / (float) STEPS;
curvePath.lineTo(calculate_x.get(i).eval(u), calculate_y.get(i)
.eval(u));
linePath.lineTo(calculate_x.get(i).eval(u), calculate_y.get(i)
.eval(u));
dashLinePaint.setShader(new LinearGradient(calculate_x.get(i).eval(u), calculate_y.get(i)
.eval(u), calculate_x.get(i).eval(u), (mHeight - bottomTextHeight - DisplayUtil.dip2px(getContext(), 20)), getResources().getColor(R.color.color_9945A0FD), getResources().getColor(R.color.color_00E0EFFF), Shader.TileMode.MIRROR));
}
//循环 需不需要画分割线eval(1) 是最大点 eval(0)是最小点
for (Integer postion : postions) {
if (postion == i && i != ITEM_SIZE - 1) {
linePath.lineTo(calculate_x.get(i).eval(1), (mHeight - bottomTextHeight - DisplayUtil.dip2px(getContext(), 20)));
linePath.lineTo(calculate_x.get(i).eval(1), calculate_y.get(i).eval(1));
}
}
// curvePath.lineTo(calculate_x.get(i).eval(0), calculate_y.get(i).eval(0));
}
//连接所有点
curvePath.lineTo(calculate_x.get(calculate_x.size() - 1).eval(1), (mHeight - bottomTextHeight - DisplayUtil.dip2px(getContext(), 20)));
curvePath.lineTo(calculate_x.get(0).eval(0), (mHeight - bottomTextHeight - DisplayUtil.dip2px(getContext(), 20)));
curvePath.lineTo(calculate_x.get(0).eval(0), calculate_y.get(0).eval(0));
//闭合路径
curvePath.close();