基于MPAndroidChart库制作K线图

最近制作一个炒币的app,类似于炒股的那种,网上资料很多很杂,最后使用github上面的MPAndroidChart库基本实现了功能。

一、介绍

MPAndroidChart库:https://github.com/PhilJay/MPAndroidChart

image

1.1支持图形

  • Line Chart 折线图
  • Bar Chart 直方图
  • Pie Chart 饼图
  • Bubble Chart 气泡图
  • Candle Stick Chart 蜡烛图(用于展示金融数据时常称为K线图)
  • Radar Chart 雷达图
  • Cubic Line Chart 立方折线图
  • Stacked Bar Chart 堆积图

1.2MPAndroid使用

  • Project level build.gradle
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
  • App level build.gradle
dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
}

二、基础实现效果图

基础实现效果图

三、核心代码

3.1、初始化表格

主要的一些属性均已写注释,部分注释可能有所偏差,具体以MPAndroidChart源码注释为准

private void initChart() {
    //K线
    ccKl.setNoDataTextColor(getResources().getColor(R.color.gray8B));//无数据时提示文字的颜色
    ccKl.setDescription(null);//取消描述
    ccKl.getLegend().setEnabled(false);//取消图例
    ccKl.setDragDecelerationEnabled(false);//不允许甩动惯性滑动  和moveView方法有冲突 设置为false
    ccKl.setMinOffset(0);//设置外边缘偏移量
    ccKl.setExtraBottomOffset(6);//设置底部外边缘偏移量 便于显示X轴
    ccKl.setScaleEnabled(false);//不可缩放
    ccKl.setAutoScaleMinMaxEnabled(true);//自适应最大最小值
    ccKl.setDrawOrder(new CombinedChart.DrawOrder[]{CombinedChart.DrawOrder.CANDLE, CombinedChart.DrawOrder.LINE}); //绘制顺序,先绘制条形再绘制条线
    
    //K线 x轴
    XAxis xac = ccKl.getXAxis();
    xac.setPosition(XAxis.XAxisPosition.BOTTOM);
    xac.setGridColor(getResources().getColor(R.color.black3B));//网格线颜色
    xac.setTextColor(getResources().getColor(R.color.gray8B));//标签颜色
    xac.setTextSize(8);//标签字体大小
    xac.setAxisLineColor(getResources().getColor(R.color.black3B));//轴线颜色
    xac.disableAxisLineDashedLine();//取消轴线虚线设置
    xac.setAvoidFirstLastClipping(true);//避免首尾端标签被裁剪
    xac.setLabelCount(5, true);//强制显示2个标签
    
    //K线 左Y轴
    YAxis axisLeft = ccKl.getAxisLeft();
    axisLeft.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);      //标签显示在内侧;OUTSIDE_CHART外侧
    axisLeft.setGridColor(getResources().getColor(R.color.black3B));  //网格颜色
    axisLeft.setTextColor(getResources().getColor(R.color.gray8B));   //文字颜色
    axisLeft.setTextSize(8);  //文字大小
    axisLeft.setLabelCount(5, true);  //label个数,强制设置标签计数
    axisLeft.enableGridDashedLine(5, 4, 0);//横向网格线设置为虚线
    
    //K线 右Y轴
    YAxis axisRight = ccKl.getAxisRight();
    //axisRight.setEnabled(false);         //不绘制右轴
    axisRight.setDrawLabels(false);      //不绘制右轴标签
    axisRight.setDrawGridLines(false);   //不绘制网格
    axisRight.setDrawAxisLine(false);    //不绘制沿轴线
    
    //蜡烛图
    candleSet = new CandleDataSet(new ArrayList<CandleEntry>(), "Kline");
    candleSet.setAxisDependency(YAxis.AxisDependency.LEFT);
    candleSet.setDrawHorizontalHighlightIndicator(false);
    candleSet.setHighlightLineWidth(0.5f);
    candleSet.setHighLightColor(getResources().getColor(R.color.brown));
    candleSet.setShadowWidth(0.7f);
    candleSet.setIncreasingColor(getResources().getColor(R.color.redEB)); //上涨设置为红色
    candleSet.setIncreasingPaintStyle(Paint.Style.FILL);   //fill:实心填充  stroke:空心描边  fill_and_stroke  填充描边
    candleSet.setDecreasingColor(getResources().getColor(R.color.green4C));//下跌设置为绿色
    candleSet.setDecreasingPaintStyle(Paint.Style.FILL);   //fill:实心填充  stroke:空心描边  fill_and_stroke  填充描边
    candleSet.setNeutralColor(getResources().getColor(R.color.redEB));
    candleSet.setShadowColorSameAsCandle(true);
    candleSet.setDrawValues(false);
    candleSet.setHighlightEnabled(false);
    //5分均线
    lineSet5 = new LineDataSet(new ArrayList<Entry>(), "MA5");
    lineSet5.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineSet5.setColor(getResources().getColor(R.color.purple));
    lineSet5.setDrawCircles(false);
    lineSet5.setDrawValues(false);
    lineSet5.setHighlightEnabled(false);
    //10分均线
    lineSet10 = new LineDataSet(new ArrayList<Entry>(), "MA10");
    lineSet10.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineSet10.setColor(getResources().getColor(R.color.yellow));
    lineSet10.setDrawCircles(false);
    lineSet10.setDrawValues(false);
    lineSet10.setHighlightEnabled(false);
    //30分均线
    lineSet30 = new LineDataSet(new ArrayList<Entry>(), "MA30");
    lineSet30.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineSet30.setColor(getResources().getColor(R.color.white));
    lineSet30.setDrawCircles(false);
    lineSet30.setDrawValues(false);
    lineSet30.setHighlightEnabled(false);
    //分时线
    lineSetMin = new LineDataSet(new ArrayList<Entry>(), "Minutes");
    lineSetMin.setAxisDependency(YAxis.AxisDependency.LEFT);
    lineSetMin.setColor(Color.WHITE);
    lineSetMin.setDrawCircles(false);
    lineSetMin.setDrawValues(false);
    lineSetMin.setDrawFilled(true);
    lineSetMin.setHighlightEnabled(false);
    lineSetMin.setFillColor(getResources().getColor(R.color.gray8B));
    lineSetMin.setFillAlpha(60);
    
    
    //成交量
    bcKl.setNoDataTextColor(getResources().getColor(R.color.gray8B));
    bcKl.setDescription(null);
    bcKl.getLegend().setEnabled(false);
    bcKl.setDragDecelerationEnabled(false);   //不允许甩动惯性滑动
    bcKl.setMinOffset(0);   //设置外边缘偏移量
    bcKl.setScaleEnabled(false);//不可缩放
    bcKl.setAutoScaleMinMaxEnabled(true);//自适应最大最小值
    //自定义Y轴标签位置
    bcKl.setRendererLeftYAxis(new InBoundYAxisRenderer(bcKl.getViewPortHandler(), bcKl.getAxisLeft(),
       bcKl.getTransformer(YAxis.AxisDependency.LEFT)));
    //设置渲染器控制颜色、偏移,以及高亮
    bcKl.setRenderer(new OffsetBarRenderer(bcKl, bcKl.getAnimator(), bcKl.getViewPortHandler(), -0.5f)
       .setHighlightWidthSize(0.5f, CommentUtil.sp2px(this, 8)));
    
    //x轴
    XAxis xAxis = bcKl.getXAxis();
    xAxis.setEnabled(false);
    
    //左Y轴
    YAxis axisLeft1 = bcKl.getAxisLeft();
    axisLeft1.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);//标签显示在内侧
    axisLeft1.setDrawAxisLine(false);
    axisLeft1.setGridColor(getResources().getColor(R.color.black3B));
    axisLeft1.setTextColor(getResources().getColor(R.color.gray8B));
    axisLeft1.setTextSize(8);
    axisLeft1.setLabelCount(2, true);
    axisLeft1.setAxisMinimum(0);
    axisLeft1.setValueFormatter(new IAxisValueFormatter() {
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
           return value == 0 ? "" : value + "";
        }
    });
    
    //右Y轴
    YAxis axisRight1 = bcKl.getAxisRight();
    //axisRight1.setEnabled(false);         //不绘制右轴
    axisRight1.setDrawLabels(false);      //不绘制右轴标签
    axisRight1.setDrawGridLines(false);   //不绘制网格
    axisRight1.setDrawAxisLine(false);    //不绘制沿轴线
    
    //柱状图
    barSet = new BarDataSet(new ArrayList<BarEntry>(), "VOL");
    barSet.setHighLightColor(getResources().getColor(R.color.brown));
    barSet.setColors(getResources().getColor(R.color.redEB), getResources().getColor(R.color.green4C));
    barSet.setDrawValues(false);
    barSet.setHighlightEnabled(false);
}

3.2、数据来源以及设置数据

private void configData() {
      
      if (combinedData == null) {
          combinedData = new CombinedData();
      }
      xValues.clear();
      List<CandleEntry> candleValues = candleSet.getValues();
      candleValues.clear();
      List<Entry> ma5Values = lineSet5.getValues();
      ma5Values.clear();
      List<Entry> ma10Values = lineSet10.getValues();
      ma10Values.clear();
      List<Entry> ma30Values = lineSet30.getValues();
      ma30Values.clear();
      List<Entry> minValues = lineSetMin.getValues();
      minValues.clear();
      List<BarEntry> barValues = barSet.getValues();
      barValues.clear();
      for (int i = 0; i < dataList.size(); i++) {
          List<String> k = dataList.get(i);
          Date d = new Date(Long.parseLong(k.get(6)) * 1000);     //6.毫秒
          String x = sdf.format(d);                               //显示日期
          if (xValues.containsValue(x)) {                         //x重复
              dataList.remove(i);
              i--;
          } else {
              xValues.put(i, x);
              float open = Float.parseFloat(k.get(4));            //4.open
              float close = Float.parseFloat(k.get(1));           //1.close
              candleValues.add(new CandleEntry(i, Float.parseFloat(k.get(2)), Float.parseFloat(k.get(3)), open, close, x)); //2.max  3.min
              minValues.add(new Entry(i, close, x));
              barValues.add(new BarEntry(i, Float.parseFloat(k.get(8)), close >= open ? 0 : 1));  //8.volume交易量
              if (i >= 4) {
                  ma5Values.add(new Entry(i, getMA(i, 5)));
                  if (i >= 9) {
                      ma10Values.add(new Entry(i, getMA(i, 10)));
                      if (i >= 29) {
                          ma30Values.add(new Entry(i, getMA(i, 30)));
                      }
                  }
              }
          }
      }
      candleSet.setValues(candleValues);
      lineSet5.setValues(ma5Values);
      lineSet10.setValues(ma10Values);
      lineSet30.setValues(ma30Values);
      lineSetMin.setValues(minValues);

      if (tlKl.getSelectedTabPosition() == 0) {
          combinedData.removeDataSet(candleSet);                      //分时图时移除蜡烛图
          combinedData.setData(new LineData(lineSetMin));             //分时线
      } else {
          combinedData.setData(new CandleData(candleSet));            //蜡烛图
          combinedData.setData(new LineData(lineSet5, lineSet10, lineSet30));    //5分线 10分线 30分线
      }

      ccKl.setData(combinedData);
      float xMax = xValues.size() - 0.5F;       //默认X轴最大值是 xValues.size() - 1
      ccKl.getXAxis().setAxisMaximum(xMax);     //使最后一个显示完整

      barSet.setValues(barValues);
      BarData barData = new BarData(barSet);
      barData.setBarWidth(1 - candleSet.getBarSpace() * 2);//使Candle和Bar宽度一致
      bcKl.setData(barData);
      bcKl.getXAxis().setAxisMaximum(xMax + (-0.5f));//保持边缘对齐
      ccKl.setVisibleXRange(52, 52);//设置显示X轴个数的上下限,竖屏固定52个
      bcKl.setVisibleXRange(52, 52);
      
 }

四、源码下载

github: https://github.com/xkdaq/KoinChart

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容