Android折线图, 双折线(带渐变色)

双折线

自定义控件双折线图效果图
![在这里插入图片描述](Android折线图, 双折线(带渐变色)_第1张图片)

上述是页面的整体效果,我这里的需求是纵坐标保持位置不变,横坐标如果日期范围超出屏幕范围则可以左右滑动,点击折线图区域有弹窗显示

  1. 带渐变色的双折线实现
  2. 纵坐标不固定高度不确定,可能是大于等于1的数
  3. 横坐标根据选择的日期动态
  4. 触摸到折线图区域,弹框显示

此处只进行折线图控件的介绍,和后面的柱状图原理一样,都是通过画布和画笔实现

折线图布局由折线图控件和外面控件组合而成,代码如下

package com.pcjz.lems.business.widget.lineChart;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import com.pcjz.lems.business.common.utils.TLog;
import com.pcjz.lems.ui.workrealname.manageequipment.CommonMethond;
import com.pcjz.lems.ui.workrealname.projectsituation.bean.LineEntity;

import java.util.ArrayList;
import java.util.List;

/**
 * created by yezhengyu on 2017/9/25 17:48
 */

public class LineChartView2 extends View {

    private List<LineEntity> mDatas;
    /**
     * 坐标轴、坐标轴字体、线条的画笔
     */
    private Paint mPaint1;
    private Paint mPaint2;
    private Paint mPaint3;
    private Paint lineOnePaint;
    private Paint lineTwoPaint;
    private int dateColor1 = Color.parseColor("#E8E8E8");
    private int dateColor2 = Color.parseColor("#999999");
    private int lineOneColor = Color.parseColor("#38AFF7");
    private int lineTwoColor = Color.parseColor("#8F74FD");
    private int mWidth;
    private int mHeight;
    private int mMaxValue;
    private int mMode;
    private int mSize;
    private Rect mBound;
    private Paint mCirclePaint;
    private Paint mPaintShader;
    private int[] shadeColors;
    private int[] shadeColors1;

    private List<Integer> mClickDistanceList = new ArrayList<>();
    private Path onePath;
    private Path twoPath;
    private Path oneShaderPath;
    private Path twoShaderPath;

    private int screenWidth;

    public LineChartView2(Context context) {
        this(context, null);
    }

    public LineChartView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LineChartView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public void setDatas(List<LineEntity> datas, int maxValue) {
        mDatas = datas;
        mMaxValue = maxValue;
        if (mMaxValue > 0 && mMaxValue <= 10) {
            mMode = 1;
        } else if (mMaxValue > 10 && mMaxValue <= 20) {
            mMode = 2;
        } else if (mMaxValue > 20 && mMaxValue <= 30) {
            mMode = 3;
        } else if (mMaxValue > 30 && mMaxValue <= 40) {
            mMode = 4;
        } else if (mMaxValue > 40 && mMaxValue <= 50) {
            mMode = 5;
        } else if (mMaxValue > 50 && mMaxValue <= 60) {
            mMode = 6;
        } else if (mMaxValue > 60 && mMaxValue <= 70) {
            mMode = 7;
        } else if (mMaxValue > 70 && mMaxValue <= 80) {
            mMode = 8;
        } else if (mMaxValue > 80 && mMaxValue <= 90) {
            mMode = 9;
        } else {
            mMode = 20;
        }
    }

    //初始化画笔
    private void init() {

        mPaint1 = new Paint();
        mPaint1.setStrokeWidth(1);
        mPaint1.setColor(dateColor1);
        mPaint1.setTextSize(dp2px(11));
        mPaint1.setTextAlign(Paint.Align.CENTER);
        mPaint1.setAntiAlias(true);
        mBound = new Rect();

        mPaint2 = new Paint();
        mPaint2.setStrokeWidth(2);
        mPaint2.setColor(dateColor2);
        mPaint2.setAntiAlias(true);

        mPaint3 = new Paint();
        mPaint3.setStyle(Paint.Style.STROKE);
        mPaint3.setStrokeWidth(1);
        mPaint3.setColor(dateColor2);
        mPaint3.setAntiAlias(true);

        mCirclePaint = new Paint();
        mCirclePaint.setAntiAlias(true);

        lineOnePaint = new Paint();
        lineOnePaint.setStrokeWidth(2);
        lineOnePaint.setStyle(Paint.Style.STROKE);
        lineOnePaint.setTextSize(dp2px(11));
        lineOnePaint.setColor(lineOneColor);

        onePath = new Path();
        oneShaderPath = new Path();

        lineTwoPaint = new Paint();
        lineTwoPaint.setStrokeWidth(2);
        lineTwoPaint.setStyle(Paint.Style.STROKE);
        lineTwoPaint.setTextSize(dp2px(11));
        lineTwoPaint.setColor(lineTwoColor);

        twoPath = new Path();
        twoShaderPath = new Path();
        /*shadeColors = new int[]{
                Color.argb(100, 255, 86, 86), Color.argb(15, 255, 86, 86),
                Color.argb(0, 255, 86, 86)};*/
        shadeColors = new int[]{Color.parseColor("#38AFF7"), Color.TRANSPARENT};
        shadeColors1 = new int[]{Color.parseColor("#8F74FD"), Color.TRANSPARENT};
        mPaintShader = new Paint();
        mPaintShader.setAntiAlias(true);
        mPaintShader.setStrokeWidth(2f);

    }

    public void initDefaultSelect(int i) {
        int size = mSize;
        int x1 = mSize / 3 + size * i - size / 2;
        int x2 = mSize / 3 + size * i + size / 2;
        if (listener != null) {
            listener.getNumber(i, (x1 + x2) / 2, mHeight);
        }
        mClickDistanceList.clear();
        mClickDistanceList.add(i);
        postInvalidate();
    }

    private void initView() {
        DisplayMetrics dm =getResources().getDisplayMetrics();
        screenWidth = dm.widthPixels;
        mWidth = getWidth();
        mHeight = getHeight();
        mSize = screenWidth / 8;
    }

    int times;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        initView();
        times++ ;
        if (times == 1) {
            if (mDatas.size() == 1) {
                initDefaultSelect(0);
            } else {
                initDefaultSelect(1);
            }
        }
        int value;
        if (mMaxValue % mMode == 0) {
            value = mMaxValue;
        } else {
            value = mMaxValue + mMaxValue % mMode;
        }
        //画坐标轴
        for (int i = 0; i <= value / mMode; i++) {
            canvas.drawLine(0, (mHeight * 8 / 9) - (7 * mHeight / 9) * i / (value / mMode), mWidth, (mHeight * 8 / 9) - (7 * mHeight / 9) * i / (value / mMode), mPaint1);
        }
        //画横坐标轴
        canvas.drawLine(0, mHeight * 8 / 9, mWidth, mHeight * 8 / 9, mPaint2);
        //画刻度线
        for (int i = 0; i < mDatas.size(); i++) {
            canvas.drawLine(mSize / 3 + mSize * i, (mHeight * 8 / 9) - 8, mSize / 3 + mSize * i, mHeight * 8 / 9, mPaint2);
        }
        String text = "作业数量(个)";
        mPaint1.setColor(dateColor2);
        mPaint1.getTextBounds(text, 0, text.length(), mBound);
        //画时间
        for (int i = 0; i < mDatas.size(); i++) {
            canvas.drawText(mDatas.get(i).getTime(), mSize / 3 + i * mSize,
                    mHeight * 8 / 9 + mBound.height() * 3 / 2, mPaint1);
        }

        //画折线
        for (int i = 0; i < mDatas.size(); i++) {
            if (mDatas.size() > 1) {
                if (i == 0) {
                    float startX = mSize / 3 + mSize * i;
                    float division = (float) (value - mDatas.get(i).getTowerCranes()) / value;
                    float startY = (division * 7 + 1) * mHeight / 9;
                    float startX1 = mSize / 3 + mSize * i;
                    float division1 = (float) (value - mDatas.get(i).getElevators()) / value;
                    float startY1 = ((division1 * 7 + 1)) * mHeight / 9;
                    onePath.moveTo(startX, startY);
                    oneShaderPath.moveTo(startX, startY);
                    twoPath.moveTo(startX1, startY1);
                    twoShaderPath.moveTo(startX1, startY1);
                } else {
                    float endX = mSize / 3 + mSize * i;
                    float division = (float) (value - mDatas.get(i).getTowerCranes()) / value;
                    float endY = (division * 7 + 1) * mHeight / 9;
                    float endX1 = mSize / 3 + mSize * i;
                    float division1 = (float) (value - mDatas.get(i).getElevators()) / value;
                    float endY1 = (division1 * 7 + 1) * mHeight / 9;
                    onePath.lineTo(endX, endY);
                    oneShaderPath.lineTo(endX, endY);
                    twoPath.lineTo(endX1, endY1);
                    twoShaderPath.lineTo(endX1, endY1);
                    if (i == mDatas.size() - 1) {
                        oneShaderPath.lineTo(i * mSize + mSize / 3, mHeight * 8 / 9);
                        oneShaderPath.lineTo(mSize / 3, mHeight * 8 / 9);
                        oneShaderPath.close();
                        twoShaderPath.lineTo(i * mSize + mSize / 3, mHeight * 8 / 9);
                        twoShaderPath.lineTo(mSize / 3, mHeight * 8 / 9);
                        twoShaderPath.close();
                    }
                }
            }
        }

        if (mDatas.size() > 1) {
            canvas.drawPath(onePath, lineOnePaint);
            canvas.drawPath(twoPath, lineTwoPaint);
            canvas.drawPath(oneShaderPath, getShadeColorPaint(shadeColors));
            canvas.drawPath(twoShaderPath, getShadeColorPaint(shadeColors1));
        }

        for (int i = 0; i < mDatas.size(); i++) {
            if (mClickDistanceList.contains(i)) {
                float centerX = mSize / 3 + i * mSize;
                float division = (float) (value - mDatas.get(i).getTowerCranes()) / value;
                float centerY = (division * 7 + 1) * mHeight / 9;
                float innerCircle = dp2px(5); //内圆半径
                float ringWidth = dp2px(1);   //圆环宽度
                //绘制外圆
                mCirclePaint.setColor(lineOneColor);
                canvas.drawCircle(centerX, centerY, innerCircle + ringWidth, mCirclePaint);
                //绘制内圆
                mCirclePaint.setColor(Color.parseColor("#FFFFFF"));
                canvas.drawCircle(centerX, centerY, innerCircle, mCirclePaint);
                float centerX1 = mSize / 3 + i * mSize;
                float division1 = (float)  (value - mDatas.get(i).getElevators()) / value;
                float centerY1 = (division1 * 7 + 1) * mHeight / 9;
                //绘制外圆
                mCirclePaint.setColor(lineTwoColor);
                canvas.drawCircle(centerX1, centerY1, innerCircle + ringWidth, mCirclePaint);
                //绘制内圆
                mCirclePaint.setColor(Color.parseColor("#FFFFFF"));
                canvas.drawCircle(centerX1, centerY1, innerCircle, mCirclePaint);

                //画虚线
                Path path = new Path();
                path.moveTo(mSize / 3 + mSize * i, mHeight * 8 / 9);
                path.lineTo(mSize / 3 + mSize * i, mHeight * 1 / 9);
                PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 1);
                mPaint3.setPathEffect(effects);
                canvas.drawPath(path, mPaint3);
            }
        }
    }

    // 修改笔的颜色
    private Paint getShadeColorPaint(int[] shadeColors) {

        Shader mShader = new LinearGradient(0, 0, 0, mHeight,
                shadeColors, null, Shader.TileMode.CLAMP);
        // 新建一个线性渐变,前两个参数是渐变开始的点坐标,第三四个参数是渐变结束的点的坐标。连接这2个点就拉出一条渐变线了,玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布,如果为空,每个颜色就是均匀分布的。最后是模式,这里设置的是循环渐变
        mPaintShader.setShader(mShader);
        return mPaintShader;
    }

    private int selectIndex = -1;
    private getNumberListener listener;

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int mChartWidthd = mSize / 3;
                for (int i = 0; i < mDatas.size(); i++) {
                    int x1 = mChartWidthd + mSize * i - mSize / 2;
                    int x2 = mChartWidthd + mSize * i + mSize / 2;
                    int y1 = mHeight * 1 / 9;
                    int y2 = mHeight * 8 / 9;
                    if (x >= x1 && x <= x2 && y >= y1 && y <= y2) {
                        selectIndex = i;
                        //传入mData中的i,横坐标,高度
                        listener.getNumber(i, (x1 + x2) / 2, mHeight);
                        mClickDistanceList.clear();
                        mClickDistanceList.add(selectIndex);
                        invalidate();
                    }
                }
                break;
            case MotionEvent.ACTION_UP:

                break;
        }
        return true;
    }

    public void setListener(getNumberListener listener) {
        this.listener = listener;
    }

    public interface getNumberListener {
        void getNumber(int number, int x, int y);
    }

    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }
}

引用控件的父布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal">
        <TextView
            android:layout_width="0dp"
            android:layout_weight="2"
            android:layout_height="match_parent"
            android:text="作业数量(个)"
            android:textColor="@color/txt_gray_shallow"
            android:textSize="10sp"
            android:gravity="center_horizontal|bottom"/>
        <TextView
            android:layout_width="0dp"
            android:layout_weight="7"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">

        <RelativeLayout
            android:id="@+id/ll_contain_number"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:orientation="vertical">

        </RelativeLayout>
        <HorizontalScrollView
            android:layout_width="0dp"
            android:layout_weight="7"
            android:layout_height="match_parent"
            android:scrollbars="none">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="horizontal">

                <RelativeLayout
                    android:id="@+id/rl_chart_contain"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent">

                    <com.pcjz.lems.business.widget.lineChart.LineChartView2
                        android:id="@+id/my_line_chart"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent" />
                </RelativeLayout>
            </LinearLayout>
        </HorizontalScrollView>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_below="@+id/my_line_chart"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <View
            android:layout_width="12dp"
            android:layout_height="12dp"
            android:background="@color/common_blue_color" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="7dp"
            android:text="塔吊起重机"
            android:textColor="@color/common_blue_color"
            android:textSize="10sp" />

        <View
            android:layout_width="12dp"
            android:layout_height="12dp"
            android:layout_marginLeft="20dp"
            android:background="@color/common_purple_color" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="7dp"
            android:text="施工升降机"
            android:textColor="@color/common_purple_color"
            android:textSize="10sp" />
    </LinearLayout>

</LinearLayout>

父控件代码

package com.pcjz.lems.business.widget.lineChart;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.pcjz.lems.R;
import com.pcjz.lems.business.common.utils.TDevice;
import com.pcjz.lems.ui.workrealname.manageequipment.CommonMethond;
import com.pcjz.lems.ui.workrealname.projectsituation.bean.LineEntity;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * created by yezhengyu on 2017/10/9 17:39
 */

public class LineChartLayout2 extends LinearLayout {
    private Context mContext;
    private List<LineEntity> mDatas;
    private LineChartView2 mLineChartView;
    private RelativeLayout relativeLayout;
    private View chartPop;
    private int maxValue;
    private RelativeLayout linearLayout;
    private int screenWidth;
    private int screenHeight;

    public LineChartLayout2(Context context) {
        this(context, null);
    }

    public LineChartLayout2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LineChartLayout2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
    }

    public void refreshLineView(List<LineEntity> datas) {
        mDatas = datas;
        View view = LayoutInflater.from(mContext).inflate(R.layout.view_line_chart2, null);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);
        setOrientation(VERTICAL);
        addView(view, lp);
        relativeLayout = (RelativeLayout) view.findViewById(R.id.rl_chart_contain);
        mLineChartView = (LineChartView2) view.findViewById(R.id.my_line_chart);
        linearLayout = (RelativeLayout) view.findViewById(R.id.ll_contain_number);
        DisplayMetrics dm =getResources().getDisplayMetrics();
        screenWidth = dm.widthPixels;
        screenHeight = dm.heightPixels;
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mLineChartView.getLayoutParams();
        params.width = initWidth(mDatas);
        mLineChartView.setLayoutParams(params);
        relativeLayout.removeView(chartPop);
        initMaxDatas();
        initLineChartView();
        postInvalidate();
        initViewXml();
    }

    private void initViewXml() {
        int intMode = CommonMethond.getInstance().getIntMode(maxValue);
        int value;
        if (maxValue % intMode == 0) {
            value = maxValue;
        } else {
            value = maxValue + maxValue % intMode;
        }
        //获取控件的高度度要减去一个状态栏的高度
        int linearLayoutHeight = screenHeight - dp2px(205) - TDevice.getStatusHeight(mContext);
        for (int i = value / intMode; i >= 0; i--) {
            TextView textView = new TextView(mContext);
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,
                    LayoutParams.WRAP_CONTENT);
            int top = (linearLayoutHeight * 8 / 9) - (7 * linearLayoutHeight / 9) * i / (value / intMode) - dp2px(5);
            params.setMargins(0, top, dp2px(6), 0);
            textView.setTextColor(getResources().getColor(R.color.txt_gray_shallow));
            textView.setTextSize(10);
            textView.setText(i * intMode + "");
            textView.setGravity(Gravity.RIGHT);
            textView.setLayoutParams(params);
            linearLayout.addView(textView);
        }
    }


    private int initWidth(List<LineEntity> datas) {
        int width = screenWidth / 8 + screenWidth * datas.size() / 8 ;
        if (width < screenWidth) {
            return screenWidth;
        } else {
            return width;
        }
    }

    private void initMaxDatas() {
        //初始化datas
        for (int i = 0; i < mDatas.size(); i++) {
            String time = mDatas.get(i).getTime();
            String subTime = time.substring(time.length() - 5, time.length());
            if (subTime != null) {
                mDatas.get(i).setTime(subTime);
            }
        }
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < mDatas.size(); i++) {
            list.add(mDatas.get(i).getElevators());
            list.add(mDatas.get(i).getTowerCranes());
        }
        Collections.sort(list);
        maxValue = list.get(list.size() - 1).intValue();
        if (maxValue <= 0) {
            maxValue = 10;
        }
    }

    private void initLineChartView() {
        mLineChartView.setDatas(mDatas, maxValue);
        mLineChartView.setListener(new LineChartView2.getNumberListener() {
            @Override
            public void getNumber(int number, int x, int y) {
                relativeLayout.removeView(chartPop);
                chartPop = LayoutInflater.from(mContext).inflate(R.layout.view_line_chart_pop, null);
                //塔吊起重机
                TextView tvTowerCrane = (TextView) chartPop.findViewById(R.id.tv_tower_crane);
                //施工升降机
                TextView tvElevator = (TextView) chartPop.findViewById(R.id.tv_elevator);
                int selectHeights = 0;
                if (mDatas != null) {
                    for (int i = 0; i < mDatas.size(); i++) {
                        int towerCranes = mDatas.get(number).getTowerCranes();
                        int elevators = mDatas.get(number).getElevators();
                        tvTowerCrane.setText(mContext.getResources().getString(R.string.number_tower_crane, towerCranes + ""));
                        tvElevator.setText(mContext.getResources().getString(R.string.number_elevator, elevators + ""));
                        if (towerCranes >= elevators) {
                            selectHeights = towerCranes;
                        } else {
                            selectHeights = elevators;
                        }
                    }
                }
                chartPop.measure(0, 0);
                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
                        RelativeLayout.LayoutParams.WRAP_CONTENT);
                if (x - chartPop.getMeasuredWidth() / 2 >= 0) {
                    layoutParams.leftMargin = x - chartPop.getMeasuredWidth() / 2;
                } else {
                    layoutParams.leftMargin = 0;
                }
                float division = (float) (maxValue - selectHeights) / maxValue;
                int topMargin = (int) ((division * 7 + 1) * y / 9 - dp2px(10) - chartPop.getMeasuredHeight());
                if (topMargin >= 0) {
                    layoutParams.topMargin = topMargin;
                } else {
                    layoutParams.topMargin = 0;
                }
                chartPop.setLayoutParams(layoutParams);
                relativeLayout.addView(chartPop);
            }
        });
    }

    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }
}

package com.pcjz.lems.ui.workrealname.projectsituation.bean;

/**
 * created by yezhengyu on 2017/9/25 17:24
 */

public class LineEntity {
    private String id;
    private String time;
    private int towerCranes;
    private int elevators;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public int getTowerCranes() {
        return towerCranes;
    }

    public void setTowerCranes(int towerCranes) {
        this.towerCranes = towerCranes;
    }

    public int getElevators() {
        return elevators;
    }

    public void setElevators(int elevators) {
        this.elevators = elevators;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

具体如何实现

  1. Android折线图, 双折线(带渐变色)_第2张图片
  2. 纵坐标和折线图背景横线均根据后台所返回折线最高点值来决定
  3. 矩形弹框的起重和升降机数量和位置根据折线控件回到的数据控制
  4. 折线图是另外一个继承view的控件,折线,背景横线,竖直虚线,两个交点圆圈,渐变色,坐标轴刻度线时间均是由画布和画笔实现

画双折线和渐变色的关键代码


            canvas.drawPath(onePath, lineOnePaint);
            canvas.drawPath(twoPath, lineTwoPaint);
            canvas.drawPath(oneShaderPath, getShadeColorPaint(shadeColors));
            canvas.drawPath(twoShaderPath, getShadeColorPaint(shadeColors1));
        
// 修改笔的颜色
    private Paint getShadeColorPaint(int[] shadeColors) {

        Shader mShader = new LinearGradient(0, 0, 0, mHeight,
                shadeColors, null, Shader.TileMode.CLAMP);
        // 新建一个线性渐变,前两个参数是渐变开始的点坐标,第三四个参数是渐变结束的点的坐标。连接这2个点就拉出一条渐变线了,玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布,如果为空,每个颜色就是均匀分布的。最后是模式,这里设置的是循环渐变
        mPaintShader.setShader(mShader);
        return mPaintShader;
    }

其他画图的方法类似

  1. 通过重写view的onTouchEvent()方法计算手指在屏幕的触摸事件,计算点击的是哪一个区域,并接口回调给父控件,父控件显示弹框。
  2. 此代码中涉及的计算较多,可以不用关心计算,只需了解思想,以及如何实现的方法即可。

你可能感兴趣的:(Android)