网站必须做诚信认证吗,wordpress主题付费,成都企业品牌网站建设,如何做好集团网站建设文章目录 一、前言二、降雨的代码三、风向代码 一、前言
开发天气相关软件时候#xff0c;做了两个自定义View#xff0c;这里进行记录#xff0c;由于涉及类较多#xff0c;这里仅包含核心代码#xff0c;需要调整后才可以运行#xff0c;自定义View范围仅包含网格相关… 文章目录 一、前言二、降雨的代码三、风向代码 一、前言
开发天气相关软件时候做了两个自定义View这里进行记录由于涉及类较多这里仅包含核心代码需要调整后才可以运行自定义View范围仅包含网格相关UI。需要注意的是横向坐标需要25个数据来表示一天24小时。最后一个数据表示0点效果如下: 降雨的效果 该效果可以通过滑动来更新顶部日期和详细降雨信息。自定义View包含天气图标、网格、横竖坐标 风向效果: 该效果可以通过滑动来更新顶部日期和详细降雨信息。自定义View包含天气图标、网格、横竖坐标
二、降雨的代码
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;import com.special.aspire.weather.R;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by YM on 2023/7/28.*/
public class WeatherColumn extends View {private float sumHeight;//总控件的高度private float sumWidth;// 总空间的宽度private Paint linePaint;//网格横线线的画笔private Paint verticalDividerLinePaint;//网格线中垂直分割线的画笔private Paint verticalDividerLinePaint2;//网格线中第二条垂直分割线的画笔private Paint mColumnPaint;//圆柱的画笔private Path mColumnPath;//圆柱的路径private Paint textPaint;//文字的画笔private Paint topImagePaint;//顶部图标的画笔private ListFloat mPrecipitationList;//降水private ListString mDateTimeList;//底部的时间private ListString mCodeList;//天气代码private float oneHeight; //每一个小段所要分成的高private float oneWidth;//每一个小段所要分成的宽private float buttomHeiht; //给底部一排日期预留出的时间private Path baseLinePath;//折线路径private ListPointF xyList;//储存定好的坐标点的集合private ListInteger topImageList new ArrayList();private ListBoolean weatherEnableList new ArrayList();// Y轴显示的列表 必须是9个private final ListString yDataList new ArrayList();// 设置进来的数据是否有效// 例windSpeedIsEnableList false false true true true true true false false// firstIndicateIndex 为2 secondIndicateIndex 6private int beforeIndicateIndex -1;private int afterIndicateIndex -1;private int ratioY 25;private float unitRation 10;// 不同降雨单位之间的比值private RainData rainData;public WeatherColumn(Context context) {super(context);initPaint();initYDataList();}public WeatherColumn(Context context, AttributeSet attrs) {super(context, attrs);initPaint();initYDataList();}private void initYDataList() {ratioY 17;if (yDataList.isEmpty()) {for (int i 0; i 17; i) {if (i % 2 0) {yDataList.add(i );}}}}public void setYDataListIn() {ratioY 25;yDataList.clear();unitRation 100f;for (int i 0; i ratioY; i 5) {float value i / unitRation;yDataList.add(value in);}invalidate();}public void setYDataListMm() {ratioY 25;yDataList.clear();unitRation 10f;for (int i 0; i ratioY; i 10) {float value i / unitRation;yDataList.add(value mm);}invalidate();}/*** 设置纵坐标显示刻度* 必须是9个** param unit 降雨单位,默认in*/public void setYDataListUnit(String unit) {switch (unit) {case mm:setYDataListMm();break;case in:setYDataListIn();break;}}/*** 初始化画笔** linpaint 线条画笔*/private void initPaint() {//画线的画笔linePaint new Paint();linePaint.setColor(Color.parseColor(#1AFFFFFF));linePaint.setAntiAlias(true);linePaint.setTextSize(dp2px(getContext(), 12));linePaint.setStrokeWidth(dp2px(getContext(), 1));verticalDividerLinePaint new Paint();verticalDividerLinePaint.setColor(Color.parseColor(#FF58FFBE));verticalDividerLinePaint.setAntiAlias(true);verticalDividerLinePaint.setStrokeWidth(dp2px(getContext(), 2));verticalDividerLinePaint2 new Paint();verticalDividerLinePaint2.setColor(Color.parseColor(#FF58FFBE));verticalDividerLinePaint2.setAntiAlias(true);verticalDividerLinePaint2.setStrokeWidth(dp2px(getContext(), 2));//文字的画笔textPaint new Paint();textPaint.setColor(Color.WHITE);textPaint.setAntiAlias(true);textPaint.setTextSize(dp2px(getContext(), 14));buttomHeiht dp2px(35);//线距离底部高度mColumnPaint new Paint(Paint.ANTI_ALIAS_FLAG);mColumnPaint.setColor(Color.parseColor(#FF58FFBE));mColumnPaint.setStrokeWidth(dp2px(getContext(), 2));mColumnPaint.setStyle(Paint.Style.FILL);mColumnPath new Path();topImagePaint new Paint(Paint.ANTI_ALIAS_FLAG);}Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);sumHeight getMeasuredHeight();sumWidth getMeasuredWidth();}Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);}private void measure() {String text min;Rect rect new Rect();textPaint.getTextBounds(text, 0, text.length(), rect);// 总共分几个高度oneHeight (sumHeight - buttomHeiht) / ratioY;TOP_MARGIN rect.height();oneWidth (sumWidth - RIGHT_MARGIN - LEFT_WIDTH) / HOR_SIZE;}int RIGHT_MARGIN dp2px(40);int LEFT_WIDTH dp2px(15);//距离左边宽度int TOP_MARGIN dp2px(13);private final int HOR_SIZE 25;private float topLineY 0;//网格顶部的Y坐标private float bottomLineY 0;//网格底部的Y坐标/*** 设置数据* WindLineData 里的所有集合数量必须是25个 从00点 到24点*/public void setWindData(RainData data) {this.mPrecipitationList data.getPrecipitation();this.mDateTimeList data.getDateTimeList();this.topImageList data.getWeatherImageResList();this.weatherEnableList data.getWeatherIsEnableList();this.mCodeList data.getCodeList();beforeIndicateIndex -1;afterIndicateIndex -1;for (int i 0; i this.weatherEnableList.size(); i) {Boolean thisValue this.weatherEnableList.get(i);// 当前为false 下一个为trueif (!thisValue i ! this.weatherEnableList.size() - 1 this.weatherEnableList.get(i 1)) {beforeIndicateIndex i 1;}// 当前为true 下一个为falseif (thisValue i ! this.weatherEnableList.size() - 1 !this.weatherEnableList.get(i 1)) {afterIndicateIndex i;}}if (this.mPrecipitationList ! null this.mPrecipitationList.size() 0 mDateTimeList ! null mDateTimeList.size() 0) {invalidate();}}Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mPrecipitationList null || mDateTimeList null) return;measure();toGetXy();//获取x和y的坐标toDrawColumn(canvas);drawWindImg(canvas);drawTouchLine(canvas);}private void toGetXy() {xyList new ArrayList();for (int i 0; i mPrecipitationList.size(); i) {
// float x i * (HOR_SIZE * 1.0f / (mPrecipitationList.size() - 1)) * oneWidth;float x i * oneWidth;float prec mPrecipitationList.get(i) * unitRation;//降雨量为0.01mm的float y (sumHeight - (oneHeight * prec));xyList.add(new PointF(x LEFT_WIDTH, y - buttomHeiht));}}/***/private void toDrawColumn(Canvas canvas) {if (xyList null || xyList.size() 0) {return;}drawLine(canvas);ListPointF NewPoints new ArrayList(xyList);baseLinePath new Path();baseLinePath.moveTo(NewPoints.get(0).x, NewPoints.get(0).y);for (int i 1; i NewPoints.size(); i) {PointF p NewPoints.get(i);int colorRes RainUtil.getWeatherColor(mCodeList.get(i),mDateTimeList.get(i));int color getResources().getColor(colorRes);drawColumn(canvas, p, color);}//绘制底部文字for (int i 0; i NewPoints.size(); i) {float x NewPoints.get(i).x;Rect rectf new Rect();textPaint.setColor(Color.WHITE);textPaint.getTextBounds(mDateTimeList.get(i), 0, mDateTimeList.get(i).length(), rectf);// 只画 00 06 12 18 这几个标志if (i % 6 0 i ! NewPoints.size() - 1) {canvas.drawText(mDateTimeList.get(i), x - rectf.width() / 2f, sumHeight - dp2px(18), textPaint);//画最下方的字体}}}private Path touchLinePath new Path();/*** 画触摸线* param canvas*/private void drawTouchLine(Canvas canvas) {if (currentTouchX -1) {verticalDividerLinePaint.setColor(Color.parseColor(#FF58FFBE));canvasDividerLine(canvas);return;}verticalDividerLinePaint.setColor(Color.parseColor(#7E58FFBE));canvas.drawLine(currentTouchX,topLineY,currentTouchX,bottomLineY,verticalDividerLinePaint2);}/*** 网格分割线* 书写右侧垂直标注动文字* param canvas*/private void drawLine(Canvas canvas) {textPaint.setColor(Color.parseColor(#B3FFFFFF));int dividerTextStartX (int) sumWidth - RIGHT_MARGIN;int startX 0;int stopX 0;if (xyList.size() ! 0) {startX (int) xyList.get(0).x;stopX (int) xyList.get(xyList.size() - 1).x;}
// String text 0;float ratioHeight (sumHeight - buttomHeiht) / yDataList.size();topLineY buttomHeiht;bottomLineY ratioHeight * (yDataList.size() - 1) buttomHeiht;//画横线for (int i 0; i yDataList.size(); i) {//因为横线是从y轴开始画的开始Y坐标为0要留出画图片的空间这里随便取一个值暂时取buttomHeihtString text yDataList.get(yDataList.size() - i - 1);//倒叙取值float y5 ratioHeight * i buttomHeiht;//可绘制高度除于总横线的数量得到每一份绘制高度然后乘以i得到每一条横线的高度canvas.drawText(text, dividerTextStartX, y5, textPaint);canvas.drawLine(startX, y5, stopX, y5, linePaint);}// 画竖线for (int i 0; i xyList.size(); i) {// // 补充最后一条线if (i % 6 0 || i xyList.size() - 1) { // 一共出4条竖线 一共24个数据canvas.drawLine(xyList.get(i).x, topLineY, xyList.get(i).x, bottomLineY, linePaint);}}Log.e(YM----,drawLine--beforeIndicateIndex:beforeIndicateIndex---afterIndicateIndex:afterIndicateIndex);canvasDividerLine(canvas);}private void canvasDividerLine(Canvas canvas){// if (currentTouchX ! -1) {//手指滑动过程中该分割线不显示
// return;
// }//这里绘制左侧阴影部分与右侧非阴影部分的分割线if (beforeIndicateIndex ! -1) {canvas.drawLine(xyList.get(beforeIndicateIndex).x, topLineY, xyList.get(beforeIndicateIndex).x, bottomLineY, verticalDividerLinePaint);}if (afterIndicateIndex ! -1) {canvas.drawLine(xyList.get(afterIndicateIndex).x, topLineY, xyList.get(afterIndicateIndex).x, bottomLineY, verticalDividerLinePaint);}}public int dp2px(float dp) {final float scale this.getResources().getDisplayMetrics().density;return (int) (dp * scale 0.5f);}private final MapInteger, Bitmap bitmaps new HashMap();SuppressLint(SuspiciousIndentation)public void drawWindImg(Canvas canvas) {for (int i 0; i topImageList.size(); i) {if (i % 2 ! 0) {// 隔一个画一个continue;}Bitmap bmp;if (bitmaps.containsKey(topImageList.get(i))) {bmp bitmaps.get(topImageList.get(i));} else {BitmapFactory.Options options new BitmapFactory.Options();options.inJustDecodeBounds true;bmp BitmapFactory.decodeResource(getResources(), topImageList.get(i));bmp Bitmap.createScaledBitmap(bmp, dp2px(24), dp2px(24), false);bitmaps.put(topImageList.get(i), bmp);}// 有效值才渲染图标if (i beforeIndicateIndex (afterIndicateIndex -1 || i afterIndicateIndex)) {canvas.drawBitmap(bmp, xyList.get(i).x - bmp.getWidth() / 2f, 0, topImagePaint);}}}//画一个顶部为圆角的矩形public void drawColumn(Canvas canvas, PointF pointF, int color) {float round dp2px(4);float width dp2px(6);float startX pointF.x - oneWidth / 2; //减横向半个位置的宽度否则会超过画布float endX startX width;float startY pointF.y;float endY bottomLineY;mColumnPaint.setColor(color);if (startY endY) { //如果开始的Y坐标与结束的Y坐标相同说明今天是晴天return;}else if (startY round endY){//开始的Y坐标加上半圆的Y坐标 大于 结束的Y坐标说明有雨但是雨不大, 这时候稍微画一点痕迹表示有雨canvas.drawRoundRect(startX, endY - round, endX, endY, round, round, mColumnPaint);return;}mColumnPath.reset();mColumnPath.moveTo(startX round, startY); // 移动到左上角圆角的起点mColumnPath.lineTo(endX - round, startY); // 绘制顶边mColumnPath.quadTo(endX, startY, endX, startY round); // 绘制右上角圆角mColumnPath.lineTo(startX width, endY); // 绘制右边mColumnPath.lineTo(startX, endY); // 绘制底边mColumnPath.lineTo(startX, startY round); // 绘制左边mColumnPath.quadTo(startX, startY, startX round, startY); // 绘制左上角圆角mColumnPath.close();canvas.drawPath(mColumnPath, mColumnPaint);}public int dp2px(Context context, float dp) {final float scale context.getResources().getDisplayMetrics().density;return (int) (dp * scale 0.5f);}public float dp2px(Resources resources, float dp) {final float scale resources.getDisplayMetrics().density;return dp * scale 0.5f;}public float sp2px(Resources resources, float sp) {final float scale resources.getDisplayMetrics().scaledDensity;return sp * scale;}private int getColumnColor(String code){return R.color.color_4D898989;}// private Boolean isTouching false;private float currentTouchX -1;private float lastTouchX -1;Overridepublic boolean onTouchEvent(MotionEvent event) {if (xyList null) {return super.onTouchEvent(event);}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:getParent().requestDisallowInterceptTouchEvent(true);return true;case MotionEvent.ACTION_MOVE:currentTouchX event.getX();if (beforeIndicateIndex ! -1) {currentTouchX Math.max(xyList.get(beforeIndicateIndex).x, currentTouchX);}if (afterIndicateIndex ! -1) {currentTouchX Math.min(xyList.get(afterIndicateIndex).x, currentTouchX);}if (currentTouchX xyList.get(0).x) {currentTouchX xyList.get(0).x;} else if (currentTouchX xyList.get(xyList.size() - 1).x) {currentTouchX xyList.get(xyList.size() - 1).x;}touchLinePath.reset();touchLinePath.moveTo(currentTouchX, (sumHeight - (oneHeight * 0)) - buttomHeiht);touchLinePath.lineTo(currentTouchX, (sumHeight - (oneHeight * yDataList.size())) - buttomHeiht);touchLinePath.lineTo(currentTouchX 3, (sumHeight - (oneHeight * yDataList.size())) - buttomHeiht);touchLinePath.moveTo(currentTouchX 3, (sumHeight - (oneHeight * 0)) - buttomHeiht);touchLinePath.close();// 限制更新频率if (Math.abs(lastTouchX - currentTouchX) 6) {lastTouchX currentTouchX;if (onTouchPositionChange ! null) {onTouchPositionChange.onChange((currentTouchX - xyList.get(0).x) / (xyList.get(xyList.size() - 1).x - xyList.get(0).x));}invalidate();}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:getParent().requestDisallowInterceptTouchEvent(false);currentTouchX -1;if (onTouchPositionChange ! null) {onTouchPositionChange.onTouchUp();}invalidate();break;}
// invalidate();return super.onTouchEvent(event);}public static class RainData {// 天气数据是否可用private ListBoolean weatherIsEnableList;//降水private ListFloat precipitation;// 时间private ListString dateTimeList;private ListString codeList;// 天气图标private ListInteger weatherImageResList;public ListBoolean getWeatherIsEnableList() {return weatherIsEnableList;}public ListFloat getPrecipitation() {return precipitation;}public ListString getDateTimeList() {return dateTimeList;}public ListInteger getWeatherImageResList() {return weatherImageResList;}public void setWeatherIsEnableList(ListBoolean weatherIsEnableList) {this.weatherIsEnableList weatherIsEnableList;}public void setPrecipitation(ListFloat precipitation) {this.precipitation precipitation;}public void setDateTimeList(ListString dateTimeList) {this.dateTimeList dateTimeList;}public void setWeatherImageResList(ListInteger winImageResList) {this.weatherImageResList winImageResList;}public ListString getCodeList() {return codeList;}public void setCodeList(ListString codeList) {this.codeList codeList;}}private OnTouchPositionChange onTouchPositionChange;public void setOnTouchPositionChange(OnTouchPositionChange onTouchPositionChange) {this.onTouchPositionChange onTouchPositionChange;}public interface OnTouchPositionChange {// 进度从0到1 0代表0点 1 代表24点void onChange(float position);void onTouchUp();}
}
三、风向代码
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.StringRes;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Created by wangchang on 2019/4/29.*/
public class WindWaveLine extends View {private float sumHeight;//总控件的高度private float sumWidth;// 总空间的宽度private float maxTime;//最大的时间 用来划分单位的 最小就是20 X1.2是为了给上方和下方预留空间private Paint linePaint;//网格横线线的画笔private Paint verticalDividerLinePaint;//网格线中垂直分割线的画笔private Paint verticalDividerLinePaint2;//网格线中第二条垂直分割线的画笔private Paint mPaint;//曲线画笔private Paint circlePaint;//第一个圆点画笔该圆点不会动private Paint circlePaint2;//第二个圆点画笔, 长按后会动private Paint textPaint;//文字的画笔private Paint topImagePaint;//顶部风向图标的画笔private ListFloat mWindSpeedList;//风速private ListString mDateTimeList;//底部的时间private float oneHeight; //每一个小段所要分成的高private float oneWidth;//每一个小段所要分成的宽private float buttomHeiht; //给底部一排日期预留出的时间private Path baseLinePath;//折线路径private float smoothness 0.27f; //折线的弯曲率private Paint baseLeftShadow;//折线下的阴影的画笔private Paint baseShadow;//折线下的阴影的画笔private ListPointF xyList;//储存定好的坐标点的集合private ListInteger topImageList new ArrayList();private ListBoolean windEnableList new ArrayList();// Y轴显示的列表 必须是9个private ListString yDataList new ArrayList();// 设置进来的数据是否有效// 例windSpeedIsEnableList false false true true true true true false false// firstIndicateIndex 为2 secondIndicateIndex 6private int beforeIndicateIndex -1;private int afterIndicateIndex -1;private WindLWaveineData windLWaveineData;private String noDataDesc ;// 左侧无数据的文字描述public WindWaveLine(Context context) {super(context);initPaint();initYDataList();}public WindWaveLine(Context context, AttributeSet attrs) {super(context, attrs);initPaint();initYDataList();}private void initYDataList() {if (yDataList.isEmpty()) {for (int i 0; i 17; i) {if (i % 2 0) {yDataList.add(i );}}}}public void setYDataListMph() {yDataList.clear();for (int i 0; i 40; i 5) {yDataList.add(i );}invalidate();}public void setYDataListKmh() {yDataList.clear();for (int i 0; i 80; i 10) {yDataList.add(i );}invalidate();}/*** 设置纵坐标显示刻度* 必须是9个** param unit 风速单位,默认m/s*/public void setYDataListUnit(String unit) {switch (unit) {case km/h:setYDataListKmh();break;case mph:setYDataListMph();break;}}public void setNoDataDesc(String noDataDesc){this.noDataDesc noDataDesc;invalidate();}public void setNoDataDesc(StringRes int noDataDescId){this.noDataDesc getResources().getString(noDataDescId);invalidate();}/*** 初始化画笔** linpaint 线条画笔*/private void initPaint() {//画线的画笔linePaint new Paint();linePaint.setColor(Color.parseColor(#1AFFFFFF));linePaint.setAntiAlias(true);linePaint.setTextSize(dp2px(getContext(), 12));linePaint.setStrokeWidth(dp2px(getContext(), 1));verticalDividerLinePaint new Paint();verticalDividerLinePaint.setColor(Color.parseColor(#1AFFFFFF));verticalDividerLinePaint.setAntiAlias(true);verticalDividerLinePaint.setStrokeWidth(dp2px(getContext(), 2));verticalDividerLinePaint2 new Paint();verticalDividerLinePaint2.setColor(Color.parseColor(#FF2D9BFE));verticalDividerLinePaint2.setAntiAlias(true);verticalDividerLinePaint2.setStrokeWidth(dp2px(getContext(), 2));//文字的画笔textPaint new Paint();textPaint.setColor(Color.WHITE);textPaint.setAntiAlias(true);textPaint.setTextSize(dp2px(getContext(), 14));circlePaint new Paint(Paint.ANTI_ALIAS_FLAG);circlePaint.setColor(Color.parseColor(#FF3EFFD4));circlePaint.setStrokeWidth(dp2px(getContext(), 2));circlePaint.setStyle(Paint.Style.STROKE);circlePaint2 new Paint(Paint.ANTI_ALIAS_FLAG);circlePaint2.setColor(Color.parseColor(#FF0061E2));circlePaint2.setStyle(Paint.Style.FILL);baseLeftShadow new Paint();baseLeftShadow.setAntiAlias(true);baseLeftShadow.setColor((Color.WHITE 0x40FFFFFF) | 0x10000000);baseLeftShadow.setStyle(Paint.Style.FILL);baseShadow new Paint();baseShadow.setAntiAlias(true);baseShadow.setColor((Color.WHITE 0x40FFFFFF) | 0x10000000);baseShadow.setStyle(Paint.Style.FILL);buttomHeiht dp2px(35);//线距离底部高度mPaint new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(Color.parseColor(#FF58FFBE));mPaint.setStrokeWidth(dp2px(getContext(), 2));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeCap(Paint.Cap.ROUND);
// mPaint.setColor(Color.parseColor(#17CAAA));topImagePaint new Paint(Paint.ANTI_ALIAS_FLAG);}Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);sumHeight getMeasuredHeight();sumWidth getMeasuredWidth();}Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);}private void measure() {maxTime 16;//最大分数为100for (int i 0; i mWindSpeedList.size(); i) {if (maxTime mWindSpeedList.get(i)) {maxTime mWindSpeedList.get(i);}}
// if (maxTime 20) {
// maxTime 20;
// }String text min;Rect rect new Rect();textPaint.getTextBounds(text, 0, text.length(), rect);// 1个time几个高度oneHeight ((sumHeight - buttomHeiht - 2 * rect.height()) / maxTime);TOP_MARGIN rect.height();oneWidth (sumWidth - RIGHT_MARGIN - LEFT_WIDTH) / HOR_SIZE;}int RIGHT_MARGIN dp2px(40);int LEFT_WIDTH dp2px(13);//距离右边宽度int TOP_MARGIN dp2px(13);// 横向分成100份private int HOR_SIZE 100;/*** 设置数据* WindLineData 里的所有集合数量必须是25个 从00点 到24点*/public void setWindData(WindLWaveineData windLWaveineData) {this.mWindSpeedList windLWaveineData.getWindSpeed();this.mDateTimeList windLWaveineData.getDateTimeList();this.topImageList windLWaveineData.getWinImageResList();this.windEnableList windLWaveineData.getWindSpeedIsEnableList();beforeIndicateIndex -1;afterIndicateIndex -1;for (int i 0; i this.windEnableList.size(); i) {Boolean thisValue this.windEnableList.get(i);// 当前为false 下一个为trueif (!thisValue i ! this.windEnableList.size() - 1 this.windEnableList.get(i 1)) {beforeIndicateIndex i 1;}// 当前为true 下一个为falseif (thisValue i ! this.windEnableList.size() - 1 !this.windEnableList.get(i 1)) {afterIndicateIndex i;}}if (this.mWindSpeedList ! null this.mWindSpeedList.size() 0 mDateTimeList ! null mDateTimeList.size() 0) {invalidate();}}Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mWindSpeedList null || mDateTimeList null) return;maxTime getMaxTime(mWindSpeedList);measure();toGetXy();//获取x和y的坐标toDrawLine(canvas);drawWindImg(canvas);drawTouchLine(canvas);drawNoDataDesc(canvas);}private void toGetXy() {xyList new ArrayList();for (int i 0; i mWindSpeedList.size(); i) {
// (HOR_SIZE*1.0f/timeList.size() 分成100份 每份有多长float x oneWidth i * (HOR_SIZE * 1.0f / (mWindSpeedList.size() - 1)) * oneWidth;float time mWindSpeedList.get(i);//每点时间float y (sumHeight - (oneHeight * time));xyList.add(new PointF(x LEFT_WIDTH, y - buttomHeiht));}}// 左侧没有数据的区域画上蒙层LinearGradient mOverlyShader new LinearGradient(0, sumHeight - maxTime * oneHeight - dp2px(4),0,sumHeight,new int[]{Color.parseColor(#00F1F9FE), Color.parseColor(#FFC4E0F2)},new float[]{0f, 1f},Shader.TileMode.REPEAT);/*** 画线*/private void toDrawLine(Canvas canvas) {if (xyList null || xyList.size() 0) {return;}drawLine(canvas);ListPointF NewPoints new ArrayList();NewPoints.addAll(xyList);float lX 0;float lY 0;baseLinePath new Path();baseLinePath.moveTo(NewPoints.get(0).x, NewPoints.get(0).y);for (int i 1; i NewPoints.size(); i) {PointF p NewPoints.get(i);PointF firstPointF NewPoints.get(i - 1);float x1 firstPointF.x lX;float y1 firstPointF.y lY;PointF secondPointF NewPoints.get(i 1 NewPoints.size() ? i 1 : i);lX (secondPointF.x - firstPointF.x) / 2 * smoothness;lY (secondPointF.y - firstPointF.y) / 2 * smoothness;float x2 p.x - lX;float y2 p.y - lY;if (y1 p.y) {y2 y1;}baseLinePath.cubicTo(x1, y1, x2, y2, p.x, p.y);}canvas.save();
// drawLeftShadow(canvas);drawLeftMask(canvas);canvas.drawPath(baseLinePath, mPaint);drawArea(canvas, NewPoints);canvas.restore();//绘制底部文字for (int i 0; i NewPoints.size(); i) {float x NewPoints.get(i).x;float y NewPoints.get(i).y;Float time mWindSpeedList.get(i);String mThumbText String.valueOf(time);
// Rect rect new Rect();
// linePaint.getTextBounds(mThumbText, 0, mThumbText.length(), rect);
// canvas.drawText(mThumbText, x - rect.width() / 2, y - dp2px(6), linePaint);//画最上面字体
// canvas.drawCircle(x, y, dp2px(3), circlePaint);
// canvas.drawCircle(x, y, dp2px(2), circlePaint2);Rect rectf new Rect();textPaint.setColor(Color.WHITE);textPaint.getTextBounds(mDateTimeList.get(i), 0, mDateTimeList.get(i).length(), rectf);// 只画 00 06 12 18 这几个标志if (i % 6 0 i ! NewPoints.size() - 1) {canvas.drawText(mDateTimeList.get(i), x - rectf.width() / 2, sumHeight - dp2px(18), textPaint);//画最下方的字体}}}//绘制一个单层的遮罩层private void drawLeftMask(Canvas canvas){baseLeftShadow.setColor(Color.parseColor(#9A10232F));//绘制左侧阴影渐变色if (beforeIndicateIndex ! -1 afterIndicateIndex ! -1) {canvas.drawRect(xyList.get(0).x, (sumHeight - (oneHeight * 16)) - buttomHeiht,xyList.get(beforeIndicateIndex).x,(sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.drawRect(xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)) - buttomHeiht,xyList.get(xyList.size() - 1).x, (sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.clipRect(xyList.get(beforeIndicateIndex).x, (sumHeight - (oneHeight * 0)) - buttomHeiht,xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)));} else if (beforeIndicateIndex ! -1) {canvas.drawRect(xyList.get(0).x, (sumHeight - (oneHeight * 16)) - buttomHeiht, xyList.get(beforeIndicateIndex).x,(sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.clipRect(xyList.get(beforeIndicateIndex).x, (sumHeight - (oneHeight * 0)) - buttomHeiht,sumWidth, (sumHeight - (oneHeight * 16)));} else if (afterIndicateIndex ! -1) {canvas.drawRect(xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)) - buttomHeiht,xyList.get(xyList.size() - 1).x, (sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.clipRect(0, (sumHeight - (oneHeight * 0)) - buttomHeiht,xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)));}}private void drawLeftShadow(Canvas canvas){//绘制左侧阴影渐变色if (beforeIndicateIndex ! -1 afterIndicateIndex ! -1) {mOverlyShader new LinearGradient(xyList.get(0).x, 0f, xyList.get(beforeIndicateIndex).x, 0f,new int[]{Color.parseColor(#00F1F9FE), Color.parseColor(#FFC4E0F2)},new float[]{0f, 1f},Shader.TileMode.REPEAT);baseLeftShadow.setShader(mOverlyShader);canvas.drawRect(xyList.get(0).x, (sumHeight - (oneHeight * 16)) - buttomHeiht,xyList.get(beforeIndicateIndex).x,(sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);mOverlyShader new LinearGradient(xyList.get(0).x, 0f, xyList.get(beforeIndicateIndex).x, 0f,new int[]{Color.parseColor(#FFC4E0F2), Color.parseColor(#00F1F9FE)},new float[]{0f, 1f},Shader.TileMode.REPEAT);baseLeftShadow.setShader(mOverlyShader);canvas.drawRect(xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)) - buttomHeiht,xyList.get(xyList.size() - 1).x, (sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.clipRect(xyList.get(beforeIndicateIndex).x, (sumHeight - (oneHeight * 0)) - buttomHeiht,xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)));} else if (beforeIndicateIndex ! -1) {mOverlyShader new LinearGradient(xyList.get(0).x, 0f, xyList.get(beforeIndicateIndex).x, 0f,new int[]{Color.parseColor(#00F1F9FE), Color.parseColor(#FFC4E0F2)},new float[]{0f, 1f},Shader.TileMode.REPEAT);baseLeftShadow.setShader(mOverlyShader);canvas.drawRect(xyList.get(0).x, (sumHeight - (oneHeight * 16)) - buttomHeiht, xyList.get(beforeIndicateIndex).x,(sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.clipRect(xyList.get(beforeIndicateIndex).x, (sumHeight - (oneHeight * 0)) - buttomHeiht,sumWidth, (sumHeight - (oneHeight * 16)));} else if (afterIndicateIndex ! -1) {mOverlyShader new LinearGradient(xyList.get(0).x, 0f, xyList.get(beforeIndicateIndex).x, 0f,new int[]{Color.parseColor(#FFC4E0F2), Color.parseColor(#00F1F9FE)},new float[]{0f, 1f},Shader.TileMode.REPEAT);baseLeftShadow.setShader(mOverlyShader);canvas.drawRect(xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)) - buttomHeiht,xyList.get(xyList.size() - 1).x, (sumHeight - (oneHeight * 0) - buttomHeiht), baseLeftShadow);canvas.clipRect(0, (sumHeight - (oneHeight * 0)) - buttomHeiht,xyList.get(afterIndicateIndex).x, (sumHeight - (oneHeight * 16)));}}private Path touchLinePath new Path();/*** 画触摸线** param canvas*/private void drawTouchLine(Canvas canvas) {if (currentTouchX -1) {return;}canvas.drawLine(currentTouchX,(sumHeight - (oneHeight * 0)) - buttomHeiht, currentTouchX,(sumHeight - (oneHeight * 16)) - buttomHeiht,verticalDividerLinePaint2);Path tempPath new Path();RectF rectF new RectF();boolean isIntersect tempPath.op(touchLinePath,baseLinePath, Path.Op.INTERSECT);tempPath.computeBounds(rectF, true);if (isIntersect) {canvas.drawCircle(rectF.left, rectF.top, dp2px(3.5f), circlePaint2);}}/*** 网格分割线* 书写右侧垂直标注动文字** param canvas*/private void drawLine(Canvas canvas) {textPaint.setColor(Color.parseColor(#B3FFFFFF));int dividerTextStartX (int) sumWidth - RIGHT_MARGIN dp2px(12);//float y16 (sumHeight - (oneHeight * 16));int startX 0;int stopX 0;if (xyList.size() ! 0) {startX (int) xyList.get(0).x;stopX (int) xyList.get(xyList.size() - 1).x;}
// String text 0;String text yDataList.get(0);float y0 (sumHeight - (oneHeight * 0));canvas.drawText(text, dividerTextStartX, sumHeight - buttomHeiht, textPaint);canvas.drawLine(startX, y0 - buttomHeiht, stopX, y0 - buttomHeiht, linePaint);//60
// text 2;text yDataList.get(1);float y2 (sumHeight - (oneHeight * 2));canvas.drawText(text, dividerTextStartX, y2 - buttomHeiht, textPaint);canvas.drawLine(startX, y2 - buttomHeiht, stopX, y2 - buttomHeiht, linePaint);// text 4;text yDataList.get(2);float y4 (sumHeight - (oneHeight * 4));canvas.drawText(text, dividerTextStartX, y4 - buttomHeiht, textPaint);canvas.drawLine(startX, y4 - buttomHeiht, stopX, y4 - buttomHeiht, linePaint);// text 6;text yDataList.get(3);float y6 (sumHeight - (oneHeight * 6));canvas.drawText(text, dividerTextStartX, y6 - buttomHeiht, textPaint);canvas.drawLine(startX, y6 - buttomHeiht, stopX, y6 - buttomHeiht, linePaint);// text 8;text yDataList.get(4);float y8 (sumHeight - (oneHeight * 8));canvas.drawText(text, dividerTextStartX, y8 - buttomHeiht, textPaint);canvas.drawLine(startX, y8 - buttomHeiht, stopX, y8 - buttomHeiht, linePaint);// text 10;text yDataList.get(5);float y10 (sumHeight - (oneHeight * 10));canvas.drawText(text, dividerTextStartX, y10 - buttomHeiht, textPaint);canvas.drawLine(startX, y10 - buttomHeiht, stopX, y10 - buttomHeiht, linePaint);// text 12;text yDataList.get(6);float y12 (sumHeight - (oneHeight * 12));canvas.drawText(text, dividerTextStartX, y12 - buttomHeiht, textPaint);canvas.drawLine(startX, y12 - buttomHeiht, stopX, y12 - buttomHeiht, linePaint);// text 14;text yDataList.get(7);float y14 (sumHeight - (oneHeight * 14));canvas.drawText(text, dividerTextStartX, y14 - buttomHeiht, textPaint);canvas.drawLine(startX, y14 - buttomHeiht, stopX, y14 - buttomHeiht, linePaint);// text 16;text yDataList.get(8);canvas.drawText(text, dividerTextStartX, y16 - buttomHeiht, textPaint);canvas.drawLine(startX, y16 - buttomHeiht, stopX, y16 - buttomHeiht, linePaint);// 画竖线for (int i 0; i xyList.size(); i) {// // 补充最后一条线if (i % 6 0 || i xyList.size() - 1) { // 一共出4条竖线 一共24个数据canvas.drawLine(xyList.get(i).x, y0 - buttomHeiht, xyList.get(i).x, y16 - buttomHeiht, linePaint);}}if (currentTouchX ! -1){//手指滑动过程中该分割线不显示return;}//这里绘制左侧阴影部分与右侧非阴影部分的分割线if (beforeIndicateIndex ! -1) {canvas.drawLine(xyList.get(beforeIndicateIndex).x, y0 - buttomHeiht, xyList.get(beforeIndicateIndex).x, y16 - buttomHeiht, verticalDividerLinePaint);canvas.drawCircle(xyList.get(beforeIndicateIndex).x, xyList.get(beforeIndicateIndex).y, dp2px(1.5f), circlePaint);}if (afterIndicateIndex ! -1) {canvas.drawLine(xyList.get(afterIndicateIndex).x, y0 - buttomHeiht, xyList.get(afterIndicateIndex).x, y16 - buttomHeiht, verticalDividerLinePaint);canvas.drawCircle(xyList.get(afterIndicateIndex).x, xyList.get(afterIndicateIndex).y, dp2px(1.5f), circlePaint);}}/*** 阴影层叠* 右侧折线底部阴影渐变* param canvas* param Points*/private void drawArea(Canvas canvas, ListPointF Points) {// sumHeight-maxTime*oneHeight-dp2px(4) -dp4是为了调整误差无特殊用处LinearGradient mShader new LinearGradient(0, sumHeight - maxTime * oneHeight - dp2px(4),0, sumHeight,new int[]{Color.parseColor(#FF58FFBE),Color.parseColor(#0058FFBE)},new float[]{0f, 1f}, Shader.TileMode.REPEAT);baseShadow.setShader(mShader);if (Points.size() 0 xyList ! null xyList.size() 0) {baseLinePath.lineTo(xyList.get(Points.size() - 1).x, sumHeight - buttomHeiht);baseLinePath.lineTo(xyList.get(0).x, sumHeight - buttomHeiht);baseLinePath.close();canvas.drawPath(baseLinePath, baseShadow);}}public int dp2px(float dp) {final float scale this.getResources().getDisplayMetrics().density;return (int) (dp * scale 0.5f);}/*** 取出时间里面的最大的一个用来计算总长度** param timeList* return*/public float getMaxTime(ListFloat timeList) {maxTime 0;for (int i 0; i timeList.size(); i) {if (maxTime timeList.get(i)) {maxTime timeList.get(i);}}if (maxTime 10) {maxTime 10;}
// maxTime * 1.2;return maxTime;}private MapInteger, Bitmap bitmaps new HashMap();SuppressLint(SuspiciousIndentation)public void drawWindImg(Canvas canvas) {for (int i 0; i topImageList.size(); i) {if (i % 2 ! 0) {// 隔一个画一个continue;}Bitmap bmp;if (bitmaps.containsKey(topImageList.get(i))) {bmp bitmaps.get(topImageList.get(i));} else {BitmapFactory.Options options new BitmapFactory.Options();options.inJustDecodeBounds true;bmp BitmapFactory.decodeResource(getResources(), topImageList.get(i));bmp Bitmap.createScaledBitmap(bmp, dp2px(24), dp2px(24), false);bitmaps.put(topImageList.get(i), bmp);}// 有效值才渲染风向图标if (i beforeIndicateIndex (afterIndicateIndex -1 || i afterIndicateIndex)) {canvas.drawBitmap(bmp, xyList.get(i).x - bmp.getWidth() / 2f, 0, topImagePaint);}}}//绘制无数据的描述该描述会在18点后显示//当时间为18点之后且没有数据时显示该描述private void drawNoDataDesc(Canvas canvas){if (beforeIndicateIndex 18) {return;}float firstX xyList.get(0).x; //00点float secondX xyList.get(18).x; //18点Rect rect new Rect();textPaint.getTextBounds(noDataDesc, 0, noDataDesc.length(), rect);float textWidth rect.width();float startX (secondX - firstX - textWidth) / 2 firstX ;textPaint.setColor(Color.WHITE);textPaint.setTextSize(dp2px(getContext(), 12));if (noDataDesc ! null !noDataDesc.isEmpty()) {canvas.drawText(noDataDesc, startX, getHeight() / 2f, textPaint);}}public int dp2px(Context context, float dp) {final float scale context.getResources().getDisplayMetrics().density;return (int) (dp * scale 0.5f);}public float dp2px(Resources resources, float dp) {final float scale resources.getDisplayMetrics().density;return dp * scale 0.5f;}public float sp2px(Resources resources, float sp) {final float scale resources.getDisplayMetrics().scaledDensity;return sp * scale;}// private Boolean isTouching false;private float currentTouchX -1;private float lastTouchX -1;Overridepublic boolean onTouchEvent(MotionEvent event) {if (xyList null) {return super.onTouchEvent(event);}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:
// currentTouchX-1;
// isTouchingtrue;getParent().requestDisallowInterceptTouchEvent(true);return true;case MotionEvent.ACTION_MOVE:currentTouchX event.getX();if (beforeIndicateIndex ! -1) {currentTouchX Math.max(xyList.get(beforeIndicateIndex).x, currentTouchX);}if (afterIndicateIndex ! -1) {currentTouchX Math.min(xyList.get(afterIndicateIndex).x, currentTouchX);}if (currentTouchX xyList.get(0).x) {currentTouchX xyList.get(0).x;} else if (currentTouchX xyList.get(xyList.size() - 1).x) {currentTouchX xyList.get(xyList.size() - 1).x;}touchLinePath.reset();touchLinePath.moveTo(currentTouchX, (sumHeight - (oneHeight * 0)) - buttomHeiht);touchLinePath.lineTo(currentTouchX, (sumHeight - (oneHeight * 16)) - buttomHeiht);touchLinePath.lineTo(currentTouchX 3, (sumHeight - (oneHeight * 16)) - buttomHeiht);touchLinePath.moveTo(currentTouchX 3, (sumHeight - (oneHeight * 0)) - buttomHeiht);touchLinePath.close();// 限制更新频率if (Math.abs(lastTouchX - currentTouchX) 6) {lastTouchX currentTouchX;if (onTouchPositionChange ! null) {onTouchPositionChange.onChange((currentTouchX - xyList.get(0).x) / (xyList.get(xyList.size() - 1).x - xyList.get(0).x));}invalidate();}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:getParent().requestDisallowInterceptTouchEvent(false);currentTouchX -1;if (onTouchPositionChange ! null) {onTouchPositionChange.onTouchUp();}invalidate();break;}
// invalidate();return super.onTouchEvent(event);}public static class WindLWaveineData {// 风速数据是否可用private ListBoolean windSpeedIsEnableList;//风速private ListFloat windSpeed;// 时间private ListString dateTimeList;// 风向图标private ListInteger winImageResList;public ListBoolean getWindSpeedIsEnableList() {return windSpeedIsEnableList;}public ListFloat getWindSpeed() {return windSpeed;}public ListString getDateTimeList() {return dateTimeList;}public ListInteger getWinImageResList() {return winImageResList;}public void setWindSpeedIsEnableList(ListBoolean windSpeedIsEnableList) {this.windSpeedIsEnableList windSpeedIsEnableList;}public void setWindSpeed(ListFloat windSpeed) {this.windSpeed windSpeed;}public void setDateTimeList(ListString dateTimeList) {this.dateTimeList dateTimeList;}public void setWinImageResList(ListInteger winImageResList) {this.winImageResList winImageResList;}}private OnTouchPositionChange onTouchPositionChange;public void setOnTouchPositionChange(OnTouchPositionChange onTouchPositionChange) {this.onTouchPositionChange onTouchPositionChange;}public interface OnTouchPositionChange {// 进度从0到1 0代表0点 1 代表24点void onChange(float position);void onTouchUp();}
}