继上次章节介绍完RecyclerChart的一些动态属性之后,本章节开始依据RecyclerChart制作新的图表,股票相关的Chart,笔者花了大约一天,制作如下的一个效果,发现换了电脑之后没有装PS,所以CandleChart的色彩自己随意取的。其实不管制作什么事务的图形,最终交给图表的不过是一堆要展示的数据而已。

下面是gif图,还有好些功用没有加,比方高亮用的是本来的RecyclerChart之前的款式。Kline作为CombineChart,还有5日、10日、20日均线的制作等以及底部一系列的比方MACD, 成交量图等待该系列后续逐渐完成

依据RecyclerChart制作一种新的图表,类似于搭积木一样,之前的心电图也是如此。制作前列一个提纲,然后依此逐一完成即可:

1.创立 StockAttr、StockBean, StockEntity.
2.创立 StockChartRecyclerView, StockChartRenderer,StockChartItemDecoration, StockValueFormatter
3. 制作主体的 drawChart. 
4. Mock Bean, Entity数据。
5. 制作 HighLight
6. 制作 XAxis
7. 制作 YAxis, 最大、最小值局部留有 padding
8. 测验添加缩放, OnScaleGestureListener; Matrix , onTouch . 依据缩放份额,调整 RecyclerChart的 displayNumber, notifyDataChange。
​
制作蜡烛图
1.计算 color, 参照上个Entry的 close大小。 界说 mStockAttrs 里的两种 color值,并且是否 Fill。
2. 画上阴线、下阴线。

图表的款式跟它所依靠的数据是相对应的,然后便是一个事务数据到Chart数据的一个转化,然后图表按照Chart数据进行制作即可。这儿的YAxis、XAxis、board, HighLight 好些跟之前的都是相通的,部分可以复用;留意一些边界上的处理。

主要是CandleChart的制作,其实里边的主体逻辑跟之前的BarChart也是类似的;这儿看看代码吧:

fun <Y : YAxis> drawStockChart(canvas: Canvas, parent: RecyclerView, yAxis: Y) {
 val parentRight = (parent.width - parent.paddingRight).toFloat()
 val parentLeft = parent.paddingLeft.toFloat()
 val childCount = parent.childCount
 for (i in 0 until childCount) {
  val child = parent.getChildAt(i)
  val stockEntry = child.tag as StockEntry
  val rectMain = getStockRectF(child, parent, yAxis, mStockAttrs, stockEntry)
  val radius = 1f
  val color = if (stockEntry.isRise) mStockAttrs.riseColor else mStockAttrs.downColor
  mBarChartPaint.color = color
  //todo 留意RTL
  drawChart(canvas, rectMain, parent.left.toFloat(), parent.right.toFloat(), radius)
  mHighLightLinePaint.color = color
  if (stockEntry.mShadowHigh > Math.max(stockEntry.mClose, stockEntry.mOpen)){
   drawTopLine(stockEntry.mShadowHigh, canvas, rectMain, yAxis, parent)
   }
  if (stockEntry.mShadowLow < Math.min(stockEntry.mClose, stockEntry.mOpen)){
   drawDownLine(stockEntry.mShadowLow, canvas, rectMain, yAxis, parent)
   }
  }
}

这儿包含了主体柱子Chart的制作,以及上阴线、下阴线的制作。

//制作上阴线、
private fun drawTopLine(value:Float, canvas: Canvas, rectF: RectF, yAxis: YAxis, parent: RecyclerView){
 canvas.save()
 val y = getYPosition(value, parent, yAxis, mStockAttrs)
 val x = (rectF.left + rectF.right)/2
 if (DecimalUtil.bigOrEquals(x, parent.left.toFloat()) && DecimalUtil.smallOrEquals(x, parent.right.toFloat())){
 canvas.drawLine(x, rectF.top, x, y, mHighLightLinePaint)
 canvas.restore()
}
}
​
//下阴线
private fun drawDownLine(value:Float, canvas: Canvas, rectF: RectF, yAxis: YAxis, parent: RecyclerView){
 canvas.save()
 val y = getYPosition(value, parent, yAxis, mStockAttrs)
 val x = (rectF.left + rectF.right)/2
 if (DecimalUtil.bigOrEquals(x, parent.left.toFloat()) && DecimalUtil.smallOrEquals(x, parent.right.toFloat())){
 canvas.drawLine(x, rectF.bottom, x, y, mHighLightLinePaint)
 canvas.restore()
}
}

制作Chart 主体,按照先前的制作,左右边界的处理。现在仍是有些bug, 先处理主逻辑,后续修正吧。

private fun drawChart(canvas: Canvas, rectF: RectF, parentLeft: Float, parentRight: Float, radius: Float) {
  
  if (DecimalUtil.smallOrEquals(rectF.right, parentLeft)) {
  //continue 会闪,原因是end == parentLeft 
   } else if (rectF.left < parentLeft && rectF.right > parentLeft) {
  
  rectF.left = parentLeft
  val path = CanvasUtil.createRectRoundPath(rectF, radius, RoundRectType.TYPE_RIGHT_TOP)
  mBarChartPaint.color = mBarChartAttrs.chartEdgeColor
  canvas.drawPath(path, mBarChartPaint)
   } else if (DecimalUtil.bigOrEquals(rectF.left, parentLeft) && DecimalUtil.smallOrEquals(rectF.right, parentRight)) {
  
  val path = CanvasUtil.createRectRoundPath(rectF, radius, RoundRectType.TYPE_ALL)
  canvas.drawPath(path, mBarChartPaint)
   } else if (DecimalUtil.smallOrEquals(rectF.left, parentRight) && rectF.right > parentRight) {
  val distance = parentRight - rectF.left
  rectF.right = rectF.left + distance
  val path = CanvasUtil.createRectRoundPath(rectF, radius, RoundRectType.TYPE_LEFT_TOP)
  mBarChartPaint.color = mBarChartAttrs.chartEdgeColor
  canvas.drawPath(path, mBarChartPaint)
   }
}

整体大致上,思路仍是蛮简单的,关于动态加载数据,高亮,Y轴在滑动过程中动态调整,随时更改Max/Min值等功用都是公用之前的逻辑。

然后便是下一章节的需要完成的均线跟Candle Chart 在一个For循环里制作,省开销,方案将均线的Bean数据放StockEntity,方便在一个For里拿去。再便是里边草稿纲要里说到的第8项,图表的缩放的功用,大致的思路如上所述,待完成。

好晚了,预备睡觉。