Android中绘制的两个天气相关的View

这篇具有很好参考价值的文章主要介绍了Android中绘制的两个天气相关的View。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

开发天气相关软件时候,做了两个自定义View,这里进行记录,由于涉及类较多,这里仅包含核心代码,需要调整后才可以运行,自定义View范围仅包含网格相关UI。需要注意的是横向坐标需要25个数据,来表示一天24小时。最后一个数据表示0点,效果如下:
降雨的效果:
该效果可以通过滑动来更新顶部日期和详细降雨信息。自定义View包含天气图标、网格、横竖坐标
Android中绘制的两个天气相关的View,View,Android,android
风向效果:
该效果可以通过滑动来更新顶部日期和详细降雨信息。自定义View包含天气图标、网格、横竖坐标
Android中绘制的两个天气相关的View,View,Android,android文章来源地址https://www.toymoban.com/news/detail-614362.html

二、降雨的代码

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 = 6
    private 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);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        sumHeight = getMeasuredHeight();
        sumWidth = getMeasuredWidth();
    }

    @Override
    protected 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 下一个为true
            if (!thisValue && i != this.weatherEnableList.size() - 1 && this.weatherEnableList.get(i + 1)) {
                beforeIndicateIndex = i + 1;
            }
            // 当前为true 下一个为false
            if (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();
        }
    }

    @Override
    protected 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,要留出画图片的空间,这里随便取一个值,暂时取buttomHeiht
            String 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;

    @Override
    public 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 = 6
    private 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);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        sumHeight = getMeasuredHeight();
        sumWidth = getMeasuredWidth();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

    }

    private void measure() {
        maxTime = 16;//最大分数为100
        for (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 下一个为true
            if (!thisValue && i != this.windEnableList.size() - 1 && this.windEnableList.get(i + 1)) {
                beforeIndicateIndex = i + 1;
            }
            // 当前为true 下一个为false
            if (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();
        }
    }

    @Override
    protected 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;

    @Override
    public 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();
    }
}

到了这里,关于Android中绘制的两个天气相关的View的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android制作天气预报软件 —— 天气查询

    天气查询功能包括信息显示和地区选择两个版块,二者均通过调用极速数据的相关接口进行实现。其中,信息显示界面作为软件首页,默认先显示系统设置的地区天气情况,用户可通过地区选择的界面进行修改信息。对于天气信息,受接口调用次数限制,系统设置每24小时更

    2024年02月12日
    浏览(43)
  • GEE(4):计算两个变量(影像)之间的相关性并绘制散点图

    最近使用Google Earth Engine(GEE)分析了一下高程和NDVI的相关性,并绘制二者的散点图,计算其决定系数。 计算时主要用到了GEE中的 图表 ui.Chart.image.byRegion() ,将研究区域内的高程和NDVI的散点图先绘制出来,再添加趋势线,计算决定系数,就可以知道二者之间的相关性有多高

    2024年02月16日
    浏览(42)
  • Android——一个简单的天气APP

    EasyWeather演示效果视频 此天气数据源采用心知天气API(试用版),免费版获取数据有限,只能获取普通的温度、湿度等,例如压力、云量、可见度等均获取不到,试用版相当于正式版,可以获取大部分数据,试用日期是14天。 首页不同城市天气页面之间的滑动采用的是 ViewPager

    2023年04月26日
    浏览(41)
  • Android实现-心知天气API接口开发(天气预报app)

    自己开发app之心知天气APP程序代码粘贴即可用。完整代码附最后。 第一步:去知心天气注册开发者账号查看自己的token。注册好登录进去--控制台---免费版--秘钥。这里的秘钥就是自己的token。(有兴趣的可以看开发文档,这里就不多介绍了)  第二步,下载素材包。点击文档

    2024年02月03日
    浏览(109)
  • uniapp - [安卓|苹果]实现App端引入高德地图,详细获取当前用户手机定位、两个地点的路线规划及相关示例代码,uniapp安卓Android平台软件下使用高德地图,获取当前位置信息及规划路线

    在uniapp安卓app端 | 苹果app端开发中,详细完成APP端引入使用高德地图插件,提供可直接复制的示例,例如获取当前定位及取到当前城市位置信息,规划两个位置的路线(规划城市2个点的路线轨迹及在地图上显示)等示例。 新手跟着教程一步步来,轻松实现此功能。 首先,

    2024年02月22日
    浏览(98)
  • 基于Android实现的天气预测APP

    网络数据源使用 Retrofit 库访问彩云 API 提供的 Webservice 接口来实现。 Retrofit 通过封装络请求和数据解析,极地提升了开发效率。并且持定义数据解析在封装所有网络请求的 API 时,我使用了协程技术来简化 Retrofit 回调的写法。 1.1.1 数据存储 本地数据源使用 SharedPreferences 持久

    2024年02月01日
    浏览(47)
  • Android 天气APP(十四)修复UI显示异常、优化业务代码逻辑、增加详情天气显示

    } public void setTmp_min(String tmp_min) { this.tmp_min = tmp_min; } public String getUv_index() { return uv_index; } public void setUv_index(String uv_index) { this.uv_index = uv_index; } public String getVis() { return vis; } public void setVis(String vis) { this.vis = vis; } public String getWind_deg() { return wind_deg; } public void setWind_deg(String w

    2024年04月25日
    浏览(35)
  • android开发之Android 自定义滑动解锁View

    自定义滑动解锁View 需求如下: 近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停。 需求效果图如下 实现效果展示 自定义view如下 /** Desc 自定义滑动解锁View Author ZY Mail sunnyfor98@gmail.com Date 2021/5/17 11:52 */ @SuppressLint(“ClickableViewAccessibility”) class SlideSwitchButton :

    2024年02月13日
    浏览(36)
  • 基于Android的天气预报系统的设计和实现

    目录 摘要 … 1 需求分析 … 2 一、开发背景… 2 二、项目需求分析… 2 总体设计 … 2 一、系统规划… 2 二、系统功能界面… 3 设置预报城市界面:… 3 2.天气显示界面: … 4 3.Widget 桌面小部件界面:… 5 三.设计目标… 6 系统设计 … 6 一、开发及运行环境… 6 二、数据库

    2024年02月08日
    浏览(60)
  • Android 天气APP(二十一)滑动改变UI(1)

    android:clickable=“true” android:padding=“@dimen/dp_12” androidx.core.widget.NestedScrollView android:layout_width=“match_parent” android:layout_height=“match_parent” android:background=“@drawable/shape_transparent_12” android:overScrollMode=“never” LinearLayout android:layout_width=“match_parent” android:layout_height=“match_pa

    2024年04月12日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包