最近在开发一款天气app,有一个功能是显示当天24小时每三个小时的气温状况,这个功能无疑要用图表来实现最好了。所以在github上找到一个国人开发的图表库,XCL-Charts。
先上效果图:

android天气温度折线图 天气预报温度曲线_图表


首先创建一个SplineChartView继承自GraphicalView,再主要实现三个方法

第一个是关于图表的渲染

private void chartRender()

{

try {

//设置绘图区默认缩进px值,留置空间显示Axis,Axistitle....     
        int [] ltrb = getBarLnDefaultSpadding();
        chart.setPadding(ltrb[0] + DensityUtil.dip2px(this.getContext(), 20), ltrb[1],
                    ltrb[2]+DensityUtil.dip2px(this.getContext(), 30), ltrb[3]);    




        //显示边框
        chart.showRoundBorder();

        //数据源   
        chart.setCategories(labels);
        chart.setDataSource(chartData);
    //  chart.setCustomLines(mCustomLineDataset);

        //坐标系
        //数据轴最大值
        chart.getDataAxis().setAxisMax(40);
        chart.getDataAxis().setAxisMin(-40);
        //数据轴刻度间隔
        chart.getDataAxis().setAxisSteps(2);

        //标签轴最大值
        chart.setCategoryAxisMax(5);    
        //标签轴最小值
        chart.setCategoryAxisMin(0);    


        //背景网格
        PlotGrid plot = chart.getPlotGrid();        
        plot.hideHorizontalLines();
        plot.hideVerticalLines();       


        chart.getPlotArea().setBackgroundColor(true, Color.GRAY);


        chart.getCategoryAxis().getAxisPaint().setColor(Color.WHITE);
        chart.getCategoryAxis().getAxisPaint().setTextSize(6);
        chart.getCategoryAxis().hideTickMarks();                    
        chart.getCategoryAxis().getTickLabelPaint().setColor(Color.WHITE);  
        chart.getCategoryAxis().getTickLabelPaint().setFakeBoldText(true);
        chart.getCategoryAxis().setTickLabelMargin(25);
        chart.getCategoryAxis().getTickLabelPaint().setTextSize(25);        

        //不使用精确计算,忽略Java计算误差,提高性能
        chart.disableHighPrecision();

        chart.disablePanMode();
        chart.hideBorder();
        chart.getPlotLegend().hide();
        chart.getDataAxis().hide();


    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.e("tag", e.toString());
    }
}

其中chart.getPlotArea().setBackgroundColor(true, Color.GRAY);是设置图表绘制区的颜色,chart.getDataAxis().setAxisMax(40);在我的app中表示能显示的最高温度是40摄氏度,chart.getDataAxis().setAxisMin(-40);表示能显示的最低温度是-40摄氏度。

第二个和第三个都是绑定数据的。public void setChartDataSet(List temps) 
 { 
 //线1的数据集 
 List linePoint1 = new ArrayList(); 
 linePoint1.add(new PointD(0d, Double.parseDouble(temps.get(0)))); 
 linePoint1.add(new PointD(1d, Double.parseDouble(temps.get(1)))); 
 linePoint1.add(new PointD(2d, Double.parseDouble(temps.get(2)))); 
 linePoint1.add(new PointD(3d, Double.parseDouble(temps.get(3)))); 
 linePoint1.add(new PointD(4d, Double.parseDouble(temps.get(4)))); 
 linePoint1.add(new PointD(5d, Double.parseDouble(temps.get(5))));
SplineData dataSeries1 = new SplineData("Go",linePoint1,
            Color.WHITE ); 
    //把线弄细点
    dataSeries1.getLinePaint().setStrokeWidth(3);
    dataSeries1.setLineStyle(XEnum.LineStyle.DASH); 
    dataSeries1.setLabelVisible(false);                 
    dataSeries1.setDotStyle(XEnum.DotStyle.RING);
    dataSeries1.getDotPaint().setColor(getResources().getColor(R.color.white));             
    dataSeries1.getPlotLine().getPlotDot().setRingInnerColor(getResources().getColor(R.color.grey));

    chartData.add(dataSeries1); 
    this.invalidate();
}

public void setChartLabels(List<String> weather){
    String[] times={"20:00\n","23:00\n","2:00\n","5:00\n","8:00\n","11:00\n"};
    for(int i=0;i<weather.size();i++){
        labels.add(times[i]+weather.get(i));
    }
    this.invalidate();
}
由于需要动态添加数据,也就是温度,这里我设置了6个时段的温度,每个时段三个小时。在setChartDataSet方法中添加了参数,dataSeries1.getLinePaint().setStrokeWidth(3);设置了绘制曲线的线宽度,dataSeries1.setLineStyle(XEnum.LineStyle.DASH)设置了曲线的类型。setChartLabels(List<String> weather)设置了横轴坐标表示什么意思,在这里表示时段和天气状态。

第四个是图批注

public void setChartAnchor(List<String> temps){
    //激活点击监听
            chart.ActiveListenItemClick();
            //为了让触发更灵敏,可以扩大5px的点击监听范围
            chart.extPointClickRange(5);        
            chart.showClikedFocus();        

            //批注
            List<AnchorDataPoint> mAnchorSet = new ArrayList<AnchorDataPoint>();


            AnchorDataPoint an2 = new AnchorDataPoint(0,0,XEnum.AnchorStyle.TOBOTTOM);
            an2.setBgColor(Color.WHITE);
            an2.setLineWidth(15);
            an2.setLineStyle(XEnum.LineStyle.DASH);

            an2.setTextColor(Color.WHITE);
            an2.setTextSize(55);
            an2.setAnchor(temps.get(0));


            AnchorDataPoint an3 = new AnchorDataPoint(0,1,XEnum.AnchorStyle.TOBOTTOM);
            an3.setBgColor(Color.WHITE);
            an3.setLineStyle(XEnum.LineStyle.DASH);
            an3.setTextColor(Color.WHITE);
            an3.setTextSize(55);
            an3.setAnchor(temps.get(1));

            //从点到底的标识线
            //从点到底的标识线
            AnchorDataPoint an4 = new AnchorDataPoint(0,2,XEnum.AnchorStyle.TOBOTTOM);
            an4.setBgColor(Color.WHITE);
            an4.setLineWidth(15);
            an4.setLineStyle(XEnum.LineStyle.DASH);
            an4.setTextColor(Color.WHITE);
            an4.setTextSize(55);
            an4.setAnchor(temps.get(2));

            AnchorDataPoint an5 = new AnchorDataPoint(0,3,XEnum.AnchorStyle.TOBOTTOM);
            an5.setBgColor(Color.WHITE);
            an5.setLineWidth(15);
            an5.setLineStyle(XEnum.LineStyle.DASH);
            an5.setTextColor(Color.WHITE);
            an5.setTextSize(55);
            an5.setAnchor(temps.get(3));

            AnchorDataPoint an6 = new AnchorDataPoint(0,4,XEnum.AnchorStyle.TOBOTTOM);
            an6.setBgColor(Color.WHITE);
            an6.setLineWidth(15);
            an6.setLineStyle(XEnum.LineStyle.DASH);
            an6.setTextColor(Color.WHITE);
            an6.setTextSize(55);
            an6.setAnchor(temps.get(4));

            AnchorDataPoint an7 = new AnchorDataPoint(0,5,XEnum.AnchorStyle.TOBOTTOM);
            an7.setBgColor(Color.WHITE);
            an7.setLineWidth(15);
            an7.setLineStyle(XEnum.LineStyle.DASH);
            an7.setTextColor(Color.WHITE);
            an7.setTextSize(55);
            an7.setAnchor(temps.get(5));

            mAnchorSet.add(an2);
            mAnchorSet.add(an3);
            mAnchorSet.add(an4);
            mAnchorSet.add(an5);
            mAnchorSet.add(an6);
            mAnchorSet.add(an7);
            chart.setAnchorDataPoint(mAnchorSet);       

            this.invalidate();
}
an2.setBgColor(Color.WHITE); 
 an2.setLineWidth(15); 
 an2.setLineStyle(XEnum.LineStyle.DASH); 
 an2.setTextColor(Color.WHITE); 
 an2.setTextSize(55); 
 an2.setAnchor(temps.get(0));


上面第一行依然是设置背景色为白色,第二行是批注线的宽度,第三行是设置批注线为虚线,第四、五行设置了批注文字的颜色和大小,第六行则是将批注文字绑定到an2上。

附上完整代码

package com.example.springweather.customview; 
 import java.util.ArrayList; 
 import java.util.LinkedList; 
 import java.util.List; 
 import org.xclcharts.chart.PointD; 
 import org.xclcharts.chart.SplineChart; 
 import org.xclcharts.chart.SplineData; 
 import org.xclcharts.common.DensityUtil; 
 import org.xclcharts.renderer.XEnum; 
 import org.xclcharts.renderer.info.AnchorDataPoint; 
 import org.xclcharts.renderer.plot.PlotGrid; 
 import org.xclcharts.view.ChartView; 
 import org.xclcharts.view.GraphicalView; 
 import com.example.springweather.R; 
 import android.content.Context; 
 import android.graphics.Canvas; 
 import android.graphics.Color; 
 import android.graphics.Paint; 
 import android.util.AttributeSet; 
 import android.util.Log; 
 public class SplineChartView extends GraphicalView { 
 private SplineChart chart = new SplineChart(); 
 //分类轴标签集合 
 private LinkedList labels = new LinkedList(); 
 private LinkedList chartData = new LinkedList(); 
 Paint pToolTip = new Paint(Paint.ANTI_ALIAS_FLAG);
public SplineChartView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    initView();
}

public SplineChartView(Context context, AttributeSet attrs){   
    super(context, attrs);   
    initView();
 }

 public SplineChartView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
 }

@Override
public void refreshChart() {
    super.refreshChart();
    labels.clear();
    chartData.clear();
}


 private void initView()
 {
        List<String> weather=new ArrayList<String>();
        for(int i=0;i<6;i++){
            weather.add("晴");
        }
        List<String> temps=new ArrayList<String>();
        for(int i=0;i<6;i++){
            temps.add("1");
        }
        setChartLabels(weather);
        setChartDataSet(temps);
        setChartAnchor(temps);

        chartRender();
 }


@Override  
protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
    super.onSizeChanged(w, h, oldw, oldh);  
   //图所占范围大小
    chart.setChartRange(w,h);
}               

protected int[] getBarLnDefaultSpadding()
{
    int [] ltrb = new int[4];
    ltrb[0] = DensityUtil.dip2px(getContext(), 0); //left   
    ltrb[1] = DensityUtil.dip2px(getContext(), 0); //top    
    ltrb[2] = DensityUtil.dip2px(getContext(), 0); //right  
    ltrb[3] = DensityUtil.dip2px(getContext(), 30); //bottom                        
    return ltrb;
}
private void chartRender()
{
    try {

        //设置绘图区默认缩进px值,留置空间显示Axis,Axistitle....     
        int [] ltrb = getBarLnDefaultSpadding();
        chart.setPadding(ltrb[0] + DensityUtil.dip2px(this.getContext(), 20), ltrb[1],
                    ltrb[2]+DensityUtil.dip2px(this.getContext(), 30), ltrb[3]);    




        //显示边框
        chart.showRoundBorder();

        //数据源   
        chart.setCategories(labels);
        chart.setDataSource(chartData);
    //  chart.setCustomLines(mCustomLineDataset);

        //坐标系
        //数据轴最大值
        chart.getDataAxis().setAxisMax(40);
        chart.getDataAxis().setAxisMin(-40);
        //数据轴刻度间隔
        chart.getDataAxis().setAxisSteps(2);

        //标签轴最大值
        chart.setCategoryAxisMax(5);    
        //标签轴最小值
        chart.setCategoryAxisMin(0);    


        //背景网格
        PlotGrid plot = chart.getPlotGrid();        
        plot.hideHorizontalLines();
        plot.hideVerticalLines();       


        chart.getPlotArea().setBackgroundColor(true, Color.GRAY);


        chart.getCategoryAxis().getAxisPaint().setColor(Color.WHITE);
        chart.getCategoryAxis().getAxisPaint().setTextSize(6);
        chart.getCategoryAxis().hideTickMarks();                    
        chart.getCategoryAxis().getTickLabelPaint().setColor(Color.WHITE);  
        chart.getCategoryAxis().getTickLabelPaint().setFakeBoldText(true);
        chart.getCategoryAxis().setTickLabelMargin(25);
        chart.getCategoryAxis().getTickLabelPaint().setTextSize(25);        

        //不使用精确计算,忽略Java计算误差,提高性能
        chart.disableHighPrecision();

        chart.disablePanMode();
        chart.hideBorder();
        chart.getPlotLegend().hide();
        chart.getDataAxis().hide();


    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.e("tag", e.toString());
    }
}

public void setChartDataSet(List<String> temps)
{
    //线1的数据集
    List<PointD> linePoint1 = new ArrayList<PointD>();              
    linePoint1.add(new PointD(0d, Double.parseDouble(temps.get(0))));   
    linePoint1.add(new PointD(1d, Double.parseDouble(temps.get(1))));                   
    linePoint1.add(new PointD(2d, Double.parseDouble(temps.get(2))));               
    linePoint1.add(new PointD(3d, Double.parseDouble(temps.get(3))));               
    linePoint1.add(new PointD(4d, Double.parseDouble(temps.get(4))));
    linePoint1.add(new PointD(5d, Double.parseDouble(temps.get(5))));

    SplineData dataSeries1 = new SplineData("Go",linePoint1,
            Color.WHITE ); 
    //把线弄细点
    dataSeries1.getLinePaint().setStrokeWidth(3);
    dataSeries1.setLineStyle(XEnum.LineStyle.DASH); 
    dataSeries1.setLabelVisible(false);                 
    dataSeries1.setDotStyle(XEnum.DotStyle.RING);
    dataSeries1.getDotPaint().setColor(getResources().getColor(R.color.white));             
    dataSeries1.getPlotLine().getPlotDot().setRingInnerColor(getResources().getColor(R.color.grey));

    chartData.add(dataSeries1); 
    this.invalidate();
}

public void setChartLabels(List<String> weather){
    String[] times={"20:00\n","23:00\n","2:00\n","5:00\n","8:00\n","11:00\n"};
    for(int i=0;i<weather.size();i++){
        labels.add(times[i]+weather.get(i));
    }
    this.invalidate();
}


public void setChartAnchor(List<String> temps){
    //激活点击监听
            chart.ActiveListenItemClick();
            //为了让触发更灵敏,可以扩大5px的点击监听范围
            chart.extPointClickRange(5);        
            chart.showClikedFocus();        

            //批注
            List<AnchorDataPoint> mAnchorSet = new ArrayList<AnchorDataPoint>();


            AnchorDataPoint an2 = new AnchorDataPoint(0,0,XEnum.AnchorStyle.TOBOTTOM);
            an2.setBgColor(Color.WHITE);
            an2.setLineWidth(15);
            an2.setLineStyle(XEnum.LineStyle.DASH);

            an2.setTextColor(Color.WHITE);
            an2.setTextSize(55);
            an2.setAnchor(temps.get(0));


            AnchorDataPoint an3 = new AnchorDataPoint(0,1,XEnum.AnchorStyle.TOBOTTOM);
            an3.setBgColor(Color.WHITE);
            an3.setLineStyle(XEnum.LineStyle.DASH);
            an3.setTextColor(Color.WHITE);
            an3.setTextSize(55);
            an3.setAnchor(temps.get(1));

            //从点到底的标识线
            //从点到底的标识线
            AnchorDataPoint an4 = new AnchorDataPoint(0,2,XEnum.AnchorStyle.TOBOTTOM);
            an4.setBgColor(Color.WHITE);
            an4.setLineWidth(15);
            an4.setLineStyle(XEnum.LineStyle.DASH);
            an4.setTextColor(Color.WHITE);
            an4.setTextSize(55);
            an4.setAnchor(temps.get(2));

            AnchorDataPoint an5 = new AnchorDataPoint(0,3,XEnum.AnchorStyle.TOBOTTOM);
            an5.setBgColor(Color.WHITE);
            an5.setLineWidth(15);
            an5.setLineStyle(XEnum.LineStyle.DASH);
            an5.setTextColor(Color.WHITE);
            an5.setTextSize(55);
            an5.setAnchor(temps.get(3));

            AnchorDataPoint an6 = new AnchorDataPoint(0,4,XEnum.AnchorStyle.TOBOTTOM);
            an6.setBgColor(Color.WHITE);
            an6.setLineWidth(15);
            an6.setLineStyle(XEnum.LineStyle.DASH);
            an6.setTextColor(Color.WHITE);
            an6.setTextSize(55);
            an6.setAnchor(temps.get(4));

            AnchorDataPoint an7 = new AnchorDataPoint(0,5,XEnum.AnchorStyle.TOBOTTOM);
            an7.setBgColor(Color.WHITE);
            an7.setLineWidth(15);
            an7.setLineStyle(XEnum.LineStyle.DASH);
            an7.setTextColor(Color.WHITE);
            an7.setTextSize(55);
            an7.setAnchor(temps.get(5));

            mAnchorSet.add(an2);
            mAnchorSet.add(an3);
            mAnchorSet.add(an4);
            mAnchorSet.add(an5);
            mAnchorSet.add(an6);
            mAnchorSet.add(an7);
            chart.setAnchorDataPoint(mAnchorSet);       

            this.invalidate();
}

@Override
public void render(Canvas canvas) {
    try{
        canvas.drawColor(Color.GRAY);
        chart.render(canvas);
    } catch (Exception e){
        Log.e("tag", e.toString());
    }
}

}