Android中绘制的两个天气相关的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 List<Float> mPrecipitationList;//降水private List<String> mDateTimeList;//底部的时间private List<String> mCodeList;//天气代码private float oneHeight; //每一个小段所要分成的高private float oneWidth;//每一个小段所要分成的宽private float buttomHeiht; //给底部一排日期预留出的时间private Path baseLinePath;//折线路径private List<PointF> xyList;//储存定好的坐标点的集合private List<Integer> topImageList = new ArrayList<>();private List<Boolean> weatherEnableList = new ArrayList<>();// Y轴显示的列表 必须是9个private final List<String> 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);List<PointF> 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 Map<Integer, 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 List<Boolean> weatherIsEnableList;//降水private List<Float> precipitation;// 时间private List<String> dateTimeList;private List<String> codeList;// 天气图标private List<Integer> weatherImageResList;public List<Boolean> getWeatherIsEnableList() {return weatherIsEnableList;}public List<Float> getPrecipitation() {return precipitation;}public List<String> getDateTimeList() {return dateTimeList;}public List<Integer> getWeatherImageResList() {return weatherImageResList;}public void setWeatherIsEnableList(List<Boolean> weatherIsEnableList) {this.weatherIsEnableList = weatherIsEnableList;}public void setPrecipitation(List<Float> precipitation) {this.precipitation = precipitation;}public void setDateTimeList(List<String> dateTimeList) {this.dateTimeList = dateTimeList;}public void setWeatherImageResList(List<Integer> winImageResList) {this.weatherImageResList = winImageResList;}public List<String> getCodeList() {return codeList;}public void setCodeList(List<String> 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 List<Float> mWindSpeedList;//风速private List<String> 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 List<PointF> xyList;//储存定好的坐标点的集合private List<Integer> topImageList = new ArrayList<>();private List<Boolean> windEnableList = new ArrayList<>();// Y轴显示的列表 必须是9个private List<String> 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);List<PointF> 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, List<PointF> 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(List<Float> 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 Map<Integer, 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;
//                isTouching=true;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 List<Boolean> windSpeedIsEnableList;//风速private List<Float> windSpeed;// 时间private List<String> dateTimeList;// 风向图标private List<Integer> winImageResList;public List<Boolean> getWindSpeedIsEnableList() {return windSpeedIsEnableList;}public List<Float> getWindSpeed() {return windSpeed;}public List<String> getDateTimeList() {return dateTimeList;}public List<Integer> getWinImageResList() {return winImageResList;}public void setWindSpeedIsEnableList(List<Boolean> windSpeedIsEnableList) {this.windSpeedIsEnableList = windSpeedIsEnableList;}public void setWindSpeed(List<Float> windSpeed) {this.windSpeed = windSpeed;}public void setDateTimeList(List<String> dateTimeList) {this.dateTimeList = dateTimeList;}public void setWinImageResList(List<Integer> 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();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/12619.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数学建模学习(5):数学建模各类题型及解题方案

一、数学建模常见的题型 总体来说&#xff0c;数学建模赛题类型主要分为&#xff1a;评价类、预测类和优化类三种&#xff0c;其中优化类是最常见的赛题类 型&#xff0c;几乎每年的地区赛或国赛美赛等均有出题&#xff0c;必须要掌握并且熟悉。 二、评价类赛题 综合评价是数学…

SIP视频对讲sip广播网关

SV-PA2是专门对行业用户需求研发的一款SIP音视频对讲&#xff0c;媒体流传输采用标准IP/RTP/RTSP协议。它很好的继承了锐科达话机稳定性好、电信级音质的优点&#xff0c;且完美兼容当下所有基于SIP的主流IPPBX/软交换/IMS平台,如Asterisk, Broadsoft, 3CX, Elastix 等。它集多…

低代码开发重要工具:jvs-flow(流程引擎)审批功能配置说明

流程引擎场景介绍 流程引擎基于一组节点与执行界面&#xff0c;通过人机交互的形式自动地执行和协调各个任务和活动。它可以实现任务的分配、协作、路由和跟踪。通过流程引擎&#xff0c;组织能够实现业务流程的优化、标准化和自动化&#xff0c;提高工作效率和质量。 在企业…

【C++】类和对象(中篇)

类和对象 类的六大默认成员函数一、构造函数1. 构造函数的概念2. 构造函数的特性 二、析构函数1. 析构函数的概念2. 析构函数的特性 三、拷贝构造函数1. 拷贝构造函数的概念2. 拷贝构造函数的特征 四、赋值运算符重载1. 运算符重载2. 赋值运算符重载 五、取地址及 const 取地址…

图神经网络(GNN)入门学习笔记(直观且简单)

文章目录 图的定义和表示可以使用图数据结构的问题将图结构用于机器学习的挑战最基本的图神经网络概述汇聚操作基于信息传递的改进图神经网络全局向量信息的利用 本篇文章参考发表于Distill上的图神经网络入门博客&#xff1a; A Gentle Introduction to Graph Neural Network…

LeetCode 2050. Parallel Courses III【记忆化搜索,动态规划,拓扑排序】困难

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

多线程之GCD应用

一些套话 GCD全称是Grand Central Dispatch&#xff0c;它是纯 C 语言&#xff0c;并且提供了非常多强大的函数 GCD的优势&#xff1a; GCD 是苹果公司为多核的并行运算提出的解决方案GCD 会自动利用更多的CPU内核&#xff08;比如双核、四核&#xff09;GCD 会自动管理线程的…

SpringBoot+Prometheus+Grafana实现系统可视化监控

场景 SpringBoot中集成Actuator实现监控系统运行状态&#xff1a; SpringBoot中集成Actuator实现监控系统运行状态_springboot actuator 获取系统运行时长_霸道流氓气质的博客-CSDN博客 基于以上Actuator实现系统监控&#xff0c;还可采用如下方案。 Prometheus Prometheu…

Selenium基础篇之屏幕截图方法

文章目录 前言一、用途1.捕获页面错误2.调试测试用例3.展示测试结果4.记录页面状态 二、方法1. save_screenshot2. get_screenshot_as_file3. get_screenshot_as_png4. get_screenshot_as_base64 总结 前言 大家好&#xff0c;我是空空star&#xff0c;本篇给大家分享一下Selen…

CMU 15-445 -- Logging Schemes - 17

CMU 15-445 -- Logging Schemes - 17 引言IndexFailure ClassificationTransaction FailuresSystem FailuresStorage Media Failures Buffer Pool PoliciesShadow Paging: No-Steal ForceWrite-Ahead Log (WAL): Steal No-ForceLogging SchemesCheckpoints小结 引言 本系列为…

IDEA配置远程docker解释器及无编码提示/关联不到python依赖问题

文章目录 1. 修改docker默认配置以支持远程连接2. 配置docker远程解释器3 .IDE配置project SDK4. 本地代码与Linux目录映射5.运行配置 1. 修改docker默认配置以支持远程连接 vim /lib/systemd/system/docker.service,修改docker启动参数 #ExecStart/usr/bin/dockerd -H fd://…

c++学习(c++11)[24]

c11 列表初始化 #include"iostream" using namepace std;int main() {int x1 1;int x2 { 2 };int x3 { 2 };vector<int> v1 {1,2,3,4,5,6};vector<int> v1 {1,2,3,4,5,6};list<int> lt1 {1,2,3,4,5,6};list<int> lt1 {1,2,3,4,5,6};au…

Python(四十九)获取列表指定元素的索引

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

汇编调用C语言定义的全局变量

在threadx移植中&#xff0c;系统的systick通过了宏定义的方式定义&#xff0c;很难对接库函数的时钟频率&#xff0c;不太利于进行维护 所以在C文件中自己定义了一个systick_Div的变量&#xff0c;通过宏定义方式设定systick的时钟频率 在汇编下要加载这个systick分频系数 …

UDS诊断协议

UDS本质上是一系列服务的集合&#xff0c;包含6大类&#xff0c;共26种。每种服务都有独立的ID&#xff0c;即SID。 请求 SID(1Byte) 参数 SID(1Byte) Sub-function(1Byte) 参数 SID DID(2Bytes) 响应 肯定响应 SID0x40(1Byte) Sub-function(根据请求是否存在) 参数…

Windows数据类型LPSTR学习

Windows在C语言的基础之上又定义了一些Windows下的数据类型&#xff1b;下面学习一下LPSTR&#xff1b; LPSTR和LPWSTR是Win32和VC所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的32位ANSI字符数组指针&#xff0c;而LPWSTR是一个指向以NULL结尾的64…

2023年基准Kubernetes报告:6个K8s可靠性失误

云计算日益成为组织构建应用程序和服务的首选目的地。尽管一年来经济不确定性的头条新闻主要集中在通货膨胀增长和银行动荡方面&#xff0c;但大多数组织预计今年的云使用和支出将与计划的相同&#xff08;45%&#xff09;&#xff0c;或高于计划的&#xff08;45%&#xff09;…

大数据Flink(五十三):Flink流处理特性、发展历史以及Flink的优势

文章目录 Flink流处理特性、发展历史以及Flink的优势 一、Flink流处理特性 二、发展历史

opencv-28 自适应阈值处理-cv2.adaptiveThreshold()

什么是自适应阈值处理? 对于色彩均衡的图像&#xff0c;直接使用一个阈值就能完成对图像的阈值化处理。但是&#xff0c;有时图像的色彩是不均衡的&#xff0c;此时如果只使用一个阈值&#xff0c;就无法得到清晰有效的阈值分割结果图像。 有一种改进的阈值处理技术&#xff…

五、控制流(2)

本章概要 returnbreak 和 continue臭名昭著的 gotoswitchswitch 字符串 return 在 Java 中有几个关键字代表无条件分支&#xff0c;这意味无需任何测试即可发生。这些关键字包括 return&#xff0c;break&#xff0c;continue 和跳转到带标签语句的方法&#xff0c;类似于其…