Android 上自定义的复式折线图(三)

Android 上自定义的复式折线图(一)

Android 上自定义的复式折线图(二)

有兴趣的话可以看下前面两篇文章,这几天也对其做了很多处理,尽量将其做的更加完美

这次修改也主要是为了然Y轴不动,表格可以进行水平滚动

其中做了以下支持:

  1. 设置左边控件的宽度
  2. 设置两个控件父控件的宽度
  3. X,Y字体跟表格的距离
  4. 设置XY轴的颜色
  5. X,Y字体颜色跟大小
  6. 表格颜色
  7. 是否显示表格
  8. 是否显示虚线
  9. 设置XY轴的文字标签
  10. 设置数据组
  11. 设置数据颜色组

效果图如下:注意第一张是表格来的,做图有问题



图一主要的实现原理:

把其弄成两个控件即左右两个,右边的用HorizontalScrollView包着,这样就可以实现水平滚动了,然后在弄个LinerLayout包着左右两个控件就OK了

首先定义一个LineViewUtil把其两个控件绑定在一起

一丶定义LineViewUtil工具类

import android.app.Activity;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

import java.util.ArrayList;

/**
 * Created by shaolin on 6/30/16.
 */
public class LineViewUtil {

    private static LineViewUtil mInstances;
    private Activity mContext;

    private LinearLayout mLayout; //父元素
    private LeftView mLeftView;
    private RightView mRightView;
    private HorizontalScrollView mScroll;

    public static synchronized LineViewUtil getInstance() {
        if (mInstances == null) {
            mInstances = new LineViewUtil();
        }
        return mInstances;
    }

    public LineViewUtil() {

    }

    public LinearLayout getView() {
        return mLayout;
    }

    public void setView(Activity context) {
        mContext = context;
        mScroll = new HorizontalScrollView(mContext);
        mScroll.setHorizontalScrollBarEnabled(false);
        mLayout = new LinearLayout(mContext);
        mLeftView = new LeftView(mContext);
        mRightView = new RightView(mContext);

        mScroll.addView(mRightView);
        mLayout.addView(mLeftView);
        mLayout.addView(mScroll);
    }

    //设置左边控件的宽度
    public void setLeftViewWidth(int leftViewWidth) {
        mLeftView.setWidth(leftViewWidth);
        mRightView.setLeftViewWidth(leftViewWidth);
    }

    //设置两个控件父控件的宽度
    public void setWidth(int partentWidth) {
        mLeftView.setPartentWidth(partentWidth);
        mRightView.setPartentWidth(partentWidth);
    }

    //X轴字体跟表格的距离
    public void setXTextToLine(int textToLine) {
        mRightView.setTextToLine(textToLine);
    }

    //Y轴字体跟表格的距离
    public void setYTextToLine(int textToLine) {
        mLeftView.setTextToLine(textToLine);
    }

    //设置XY轴的颜色
    public void setXYColor(int XYColor) {
        mLeftView.setXYColor(XYColor);
        mRightView.setXYColor(XYColor);
    }

    public void setXTextColor(int XTextColor) {
        mRightView.setXTextColor(XTextColor);
    }

    public void setYTextColor(int YTextColor) {
        mLeftView.setYTextColor(YTextColor);
    }

    //如果是多条数据图这里是数据的默认颜色,即没有设置数据颜色组时会起作用
    public void setDefDataColor(int dataColor) {
        mRightView.setDefDataColor(dataColor);
    }

    public void setXTextSize(int XTextSize) {
        mRightView.setXTextSize(XTextSize);
    }

    public void setYTextSize(int YTextSize) {
        mLeftView.setYTextSize(YTextSize);
    }

    public void setGridColor(int gridColor) {
        mRightView.setGridColor(gridColor);
    }

    //是否虚线
    public void setShowDashed(boolean isDottedLine) {
        mRightView.setShowDashed(isDottedLine);
    }

    public void setShowGrid(boolean isShowGrid) {
        mLeftView.setShowGrid(isShowGrid);
        mRightView.setShowGrid(isShowGrid);
    }

    //设置XY轴的文字标签
    public void setXYLabel(ArrayList<String> xlabel, ArrayList<String> ylabel) {
        mLeftView.setYLabel(ylabel);
        mRightView.setXYLabel(xlabel, ylabel);
    }

    //设置数据组
    public void setDataList(ArrayList<ArrayList<Integer>> dataLists) {
        mRightView.setDataList(dataLists);
    }

    //设置数据颜色组
    public void setDataColorList(ArrayList<Integer> dataColorList) {
        mRightView.setDataColorList(dataColorList);
    }

}
二丶左边的Y轴标签控件LeftView

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

import java.util.ArrayList;

/**
 * Created by shaolin on 6/28/16.
 */
public class LeftView extends View {

    private static final String TAG = "LeftView";

    private int Xscale;
    private int Yscale;
    private int Xpoint;
    private int Ypoint;

    // Y轴上面的显示文字
    private ArrayList<String> YLabel;
    private int YTextSize = 8;
    private int YTextColor = Color.WHITE;

    private int defXCount = 10;
    private int width = 40;
    private int height;
    private int partentWidth;
    private int textToLine;

    private int XYColor = Color.WHITE;
    //是否显示表格
    private boolean isGrid = false;

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

    public LeftView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initSize();
    }

    private void initSize() {
        YLabel = new ArrayList<>();
        setYTextSize(YTextSize);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Xscale = (partentWidth - width * 2) / defXCount;
        Yscale = Xscale / 2;

        height = Yscale * YLabel.size() + Yscale;

        Xpoint = width;
        Ypoint = Yscale * YLabel.size();
        Log.e(TAG, "width:" + width + "  ;height:" + height);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint p1 = new Paint();
        p1.setStyle(Paint.Style.STROKE);
        p1.setAntiAlias(true);
        p1.setColor(XYColor);
        p1.setStrokeWidth(2);
        drawYText(canvas);
        if (!isGrid) {
            drawYLine(canvas, p1);
        }
    }

    private void drawYText(Canvas canvas) {
        Paint p = new Paint();
        p.setAntiAlias(true);
        p.setColor(YTextColor);
        p.setTextSize(YTextSize);
        p.setTextAlign(Paint.Align.RIGHT);
        // 纵轴数据
        for (int i = 0; i < YLabel.size(); i++) {
            int startY = Ypoint - i * Yscale;
            canvas.drawText(this.YLabel.get(i), width - 10 - textToLine, startY + Yscale / 4, p);
        }
    }

    //画纵轴
    private void drawYLine(Canvas canvas, Paint p) {
        p.setColor(XYColor);
        float stopX = Xpoint;
        float stopY = Ypoint - Yscale * (YLabel.size() - 1);
        canvas.drawLine(Xpoint, Ypoint, stopX, stopY, p);
        // Y轴最后是否有箭头
        canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY + Yscale / 3, p);
//        canvas.drawLine(stopX, stopY, stopX + Xscale / 6, stopY + Yscale / 3, p);
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setTextToLine(int textToLine) {
        this.textToLine = textToLine;
    }

    public void setYLabel(ArrayList<String> YLabel) {
        this.YLabel = YLabel;
    }

    public void setPartentWidth(int partentWidth) {
        this.partentWidth = partentWidth;
    }

    public void setYTextSize(int YTextSize) {
        this.YTextSize = setDimensionSP(YTextSize);
    }

    public void setYTextColor(int YTextColor) {
        this.YTextColor = YTextColor;
    }

    public void setXYColor(int XYColor) {
        this.XYColor = XYColor;
    }

    public void setShowGrid(boolean isGrid) {
        this.isGrid = isGrid;
    }

    public int setDimensionDIP(int size) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, 
                Resources.getSystem().getDisplayMetrics());
    }

    public int setDimensionSP(int size) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, 
                Resources.getSystem().getDisplayMetrics());
    }
}
三丶 Y轴右边的表格等数据RightView控件

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

import java.util.ArrayList;

/**
 * Created by shaolin on 6/28/16.
 */
public class RightView extends View {

    private static final String TAG = "RightView";

    // 原点坐标
    private int Xpoint;
    private int Ypoint;

    // X,Y轴的单位长度,即表格中的正方形的宽高
    private int Yscale;
    private int Xscale;

    //是否显示表格
    private boolean isGrid = false;
    //是否展示表格为虚线
    private boolean isDashed = false;

    // X最左边跟Y左下面的线的颜色
    private int XYColor = Color.WHITE;
    // X轴字体的颜色
    private int XTextColor = Color.WHITE;
    // 表格字体的颜色
    private int GridColor = Color.WHITE;
    // 数据字体的颜色
    private int defDataColor = Color.WHITE;

    private int XTextSize = 8;

    // X轴上面的显示文字
    private ArrayList<String> XLabel;
    // Y轴上面的显示文字
    private ArrayList<String> YLabel;
    // 曲线数据
    private ArrayList<ArrayList<Integer>> dataLists;
    private ArrayList<Integer> dataColorList;
    // 单前数据
    private ArrayList<Integer> dataList;
    private int color;

    private int defXCount = 10;
    private int dataCount;

    private int width;
    private int height;
    private int partentWidth;

    private int leftViewWidth = 40;
    private int textToLine;


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

    public RightView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initSize();
    }

    private void initSize() {
        XLabel = new ArrayList<>();
        YLabel = new ArrayList<>();
        dataColorList = new ArrayList<>();
        dataList = new ArrayList<>();
        dataLists = new ArrayList<>();
        setXTextSize(XTextSize);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (dataLists.size() > 0 && partentWidth > 0) {
            Xscale = (partentWidth - leftViewWidth * 2) / defXCount;
            Yscale = Xscale / 2;
            if (dataLists.get(0).size() <= defXCount) {
                dataCount = defXCount;
            } else {
                dataCount = dataLists.get(0).size();
            }
        }

        width = Xscale * dataCount + leftViewWidth;
        height = Yscale * YLabel.size() + Yscale + XTextSize;

        Xpoint = 0;
        Ypoint = Yscale * YLabel.size();
        Log.e(TAG, "width:" + width + " ;height:" + height);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint p1 = new Paint();
        p1.setStyle(Paint.Style.STROKE);
        p1.setAntiAlias(true);
        p1.setColor(XYColor);
        p1.setStrokeWidth(2);
        if (isGrid) {
            this.drawTable(canvas);
        } else {
            this.drawXLine(canvas, p1);
            this.drawYLine(canvas, p1);
        }
        if (dataLists != null) {
            for (int i = 0; i < dataLists.size(); i++) {
                this.drawData(canvas, i);
            }
        }
    }

    // 画表格
    private void drawTable(Canvas canvas) {
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(GridColor);
        Path path = new Path();
        if (isDashed) {
            PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 1);//画虚线
            paint.setPathEffect(effects);
        }
        int startX = 0;
        int startY = 0;
        int stopX = 0;
        int stopY = 0;
        // 纵向线
        for (int i = 0; i <= dataCount; i++) {
            startX = Xpoint + i * Xscale;
            startY = Ypoint;
            stopY = Ypoint - (this.YLabel.size() - 1) * Yscale;
            if (i != 0) {
                path.moveTo(startX - Xscale / 2, startY);
                path.lineTo(startX - Xscale / 2, stopY);
                canvas.drawPath(path, paint);
            }
            path.moveTo(startX, startY);
            path.lineTo(startX, stopY);
            canvas.drawPath(path, paint);
        }

        // 横向线
        for (int i = 0; i < YLabel.size(); i++) {
            startX = Xpoint;
            startY = Ypoint - i * Yscale;
            stopX = Xpoint + (dataCount) * Xscale;
            path.moveTo(startX, startY);
            path.lineTo(stopX, startY);
            paint.setColor(GridColor);
            canvas.drawPath(path, paint);
        }
    }

    //画纵轴
    private void drawYLine(Canvas canvas, Paint p) {
        p.setColor(XYColor);
        float stopX = Xpoint;
        float stopY = Ypoint - Yscale * (YLabel.size() - 1);
        canvas.drawLine(Xpoint, Ypoint, stopX, stopY, p);
        // Y轴最后是否有箭头
//        canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY + Yscale / 3, p);
        canvas.drawLine(stopX, stopY, stopX + Xscale / 6, stopY + Yscale / 3, p);
    }

    // 画横轴
    private void drawXLine(Canvas canvas, Paint p) {
        p.setColor(XYColor);
        float stopX = Xpoint + Xscale * dataCount;
        float stopY = Ypoint;
        canvas.drawLine(Xpoint, Ypoint, stopX, stopY, p);
        // X轴最后是否有箭头
        canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY - Yscale / 3, p);
        canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY + Yscale / 3, p);
    }

    // 画数据
    private void drawData(Canvas canvas, int pos) {
        dataList = dataLists.get(pos);
        if (dataColorList.size() == 0) {
            color = defDataColor;
        } else {
            color = dataColorList.get(pos);
        }

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

       /* // 纵轴数据
        for (int i = 0; i < YLabel.size(); i++) {
            int startY = Ypoint - i * Yscale;
            p.setColor(YTextColor);
            p.setTextSize(XTextSize);
            p.setTextAlign(Paint.Align.RIGHT);
            canvas.drawText(this.YLabel.get(i), this.Margin / 4 * 3 + marginLeft,
                    startY + this.Margin / 4, p);
        }*/

        //横轴数据
        for (int i = 0; i < dataCount; i++) {
            int startX = Xpoint + i * Xscale;
            p.setColor(XTextColor);
            p.setTextSize(XTextSize);
            p.setTextAlign(Paint.Align.CENTER);
            String text = "";
            if (i < XLabel.size()) {
                text = this.XLabel.get(i);
            }
            canvas.drawText(text, startX + Xscale / 2, Ypoint + XTextSize + 5 + textToLine, p);

            p.setColor(dataColorList.size() > 0 ? color : defDataColor);
            if (i < XLabel.size()) {
                canvas.drawCircle(startX + Xscale / 2, calY(dataList.get(i)), 4, p);
            }
            if (i < XLabel.size() - 1) {
                canvas.drawLine(startX + Xscale / 2, calY(dataList.get(i)),
                        Xpoint + (i + 1) * Xscale + Xscale / 2, calY(dataList.get(i + 1)), p);
            }
        }
    }

    private int calY(int y) {
        int y0 = 0;
        int y1 = 0;
        try {
            y0 = Integer.parseInt(YLabel.get(0));
            y1 = Integer.parseInt(YLabel.get(1));
        } catch (Exception e) {
            return 0;
        }
        try {
            return Ypoint - ((y - y0) * Yscale / (y1 - y0));
        } catch (Exception e) {
            return 0;
        }
    }

    public void setLeftViewWidth(int leftViewWidth) {
        this.leftViewWidth = leftViewWidth;
    }

    public void setPartentWidth(int partentWidth) {
        this.partentWidth = partentWidth;
    }

    public void setTextToLine(int textToLine) {
        this.textToLine = textToLine;
    }

    public void setXYColor(int XYColor) {
        this.XYColor = XYColor;
    }

    public void setXTextColor(int XTextColor) {
        this.XTextColor = XTextColor;
    }

    public void setGridColor(int gridColor) {
        this.GridColor = gridColor;
    }

    public void setDefDataColor(int defDataColor) {
        this.defDataColor = defDataColor;
    }

    public void setXTextSize(int XTextSize) {
        this.XTextSize = setDimensionSP(XTextSize);
    }

    public void setShowDashed(boolean isDashed) {
        this.isDashed = isDashed;
    }

    public void setShowGrid(boolean isGrid) {
        this.isGrid = isGrid;
    }

    public void setXYLabel(ArrayList<String> xlabel, ArrayList<String> ylabel) {
        this.XLabel = xlabel;
        this.YLabel = ylabel;
    }

    public void setDataList(ArrayList<ArrayList<Integer>> dataLists) {
        this.dataLists = dataLists;
        postInvalidate();
    }

    public void setDataColorList(ArrayList<Integer> dataColorList) {
        this.dataColorList = dataColorList;
    }


    public int setDimensionDIP(int size) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, 
                  Resources.getSystem().getDisplayMetrics());
    }

    public int setDimensionSP(int size) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, 
                  Resources.getSystem().getDisplayMetrics());
    }
}
四丶这里在弄个例子出来是不是就比较完美了,这就来...

MainActivity.java

public class MainActivity extends Activity {

    private ArrayList<Integer> colorList = new ArrayList<>();
    private ArrayList<String> XLabel = new ArrayList<>();
    private ArrayList<String> YLabel = new ArrayList<>();

    private LineViewUtil mUtil;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
        mUtil = LineViewUtil.getInstance();
        mUtil.setView(this);
        mUtil.setXYLabel(XLabel, YLabel);
        mUtil.setDataColorList(colorList);
        mUtil.setWidth(getLineViewWidth());
        mUtil.setShowGrid(true);
        mUtil.setGridColor(Color.LTGRAY);
        randSet(mUtil);

        LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
        layout.addView(mUtil.getView());
    }

    private void initData() {
        colorList.add(getResources().getColor(R.color.using_before));
        colorList.add(getResources().getColor(R.color.using_after));
        for (int i = 0; i < 15; i++) {
            XLabel.add(String.valueOf(i + 1));
        }
        for (int i = 0; i < 11; i++) {
            YLabel.add(String.valueOf(i * 10));
        }
    }

    private void randSet(LineViewUtil util) {
        ArrayList<ArrayList<Integer>> dataLists = new ArrayList<>();

        ArrayList<Integer> dataList1 = new ArrayList<Integer>();
        int random1 = (int) (Math.random() * 99 + 1);
        for (int i = 0; i < XLabel.size(); i++) {
            dataList1.add((int) (Math.random() * random1));
        }

        ArrayList<Integer> dataList2 = new ArrayList<Integer>();
        int random2 = (int) (Math.random() * 99 + 1);
        for (int i = 0; i < XLabel.size(); i++) {
            dataList2.add((int) (Math.random() * random2));
        }
        dataLists.add(dataList1);
        dataLists.add(dataList2);
        util.setDataList(dataLists);
    }

    private int getLineViewWidth() {
        return getWindowManager().getDefaultDisplay().getWidth();
    }
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#55000000"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" />

</LinearLayout>
colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="using_before">#f6e749</color>
    <color name="using_after">#7ae6fe</color>
</resources>

Demo:http://download.csdn.net/detail/qq_30552993/9564198

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值