“MPAndroidChart”에서 BarChart를 사용하며 일부 사항을 작성
디자인 요구 사항에 따라 작업 중 발생한 이슈 사항을 기록 및 구현
이전 포스트에서는 이슈 사항 중 마커([MPAndroidChart] BarChart Custom (1))에 관련된 내용을 작성 이번 포스트에서는 바차트의 라운드 처리에 대한 내용을 작성
요구사항
- 애니메이션처리 필요
- 바차트 상단 라운드 처리
- 스크롤 기능
- 마커 추가
구현 순서
- 기본 바차트를 구현 기본적으로 라이브러리에서 지원하는 기능을 검토
- x, y 축을 포함하여 기본기능을 적용
- 커스텀으로 처리 가능한 영을 체크 구현 방법에 대한 검토 진행
문제 및 해결
- 바차트의 경우 라운드 처리에 대한 기능을 가지고 있지 않아 “BarChartRenderer”를 상속받아 바상단의 라운드 처리를 진행
- 아래 함수에서 DataSet을 통해 바의 위치와 바의 형태를 Canvas에 그림
1
override fun drawDataSet(c: Canvas, dataSet: IBarDataSet, index: Int)
위 함수 애서 아래와 같이 Rect를 통해 바를 그리는 형태로 구현 되어 있음
1
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2], buffer.buffer[j + 3], mRenderPaint);
해당 부분을 상단 곡선 형태로 draw하는 방식으로 코드의 수정이 필요 했음 radius의 경우 left([j])
, right([j+2])
인 값을 (right - left)/2
해당 공식을 통해 구함 width를 구하지 않고 임의의 값을 사용할 경우 완전한 곡선이 안나올 수 있어 with를 구한뒤 최적의 radius를 구한다.
1
2
3
4
5
6
7
8
9
val path2 = roundRect(
RectF(
buffer.buffer[j],
buffer.buffer[j + 1],
buffer.buffer[j + 2],
buffer.buffer[j + 3]
), radius, radius, tl = true, tr = true, br = false, bl = false
)
c.drawPath(path2, mRenderPaint)
일부코드
roundRect 함수의 코드는 아래와 같이 구현되어 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private fun roundRect(
rect: RectF, rx: Float, ry: Float, tl: Boolean, tr: Boolean, br: Boolean, bl: Boolean
): Path {
var rx = rx
var ry = ry
val top = rect.top
val left = rect.left
val right = rect.right
val bottom = rect.bottom
val path = Path()
if (rx < 0) rx = 0f
if (ry < 0) ry = 0f
val width = right - left
val height = bottom - top
if (rx > width / 2) rx = width / 2
if (ry > height / 2) ry = height / 2
val widthMinusCorners = width - 2 * rx
val heightMinusCorners = height - 2 * ry
path.moveTo(right, top + ry)
if (tr) path.rQuadTo(0f, -ry, -rx, -ry) //top-right corner
else {
path.rLineTo(0f, -ry)
path.rLineTo(-rx, 0f)
}
path.rLineTo(-widthMinusCorners, 0f)
if (tl) path.rQuadTo(-rx, 0f, -rx, ry) //top-left corner
else {
path.rLineTo(-rx, 0f)
path.rLineTo(0f, ry)
}
path.rLineTo(0f, heightMinusCorners)
if (bl) path.rQuadTo(0f, ry, rx, ry) //bottom-left corner
else {
path.rLineTo(0f, ry)
path.rLineTo(rx, 0f)
}
path.rLineTo(widthMinusCorners, 0f)
if (br) path.rQuadTo(rx, 0f, rx, -ry) //bottom-right corner
else {
path.rLineTo(rx, 0f)
path.rLineTo(0f, -ry)
}
path.rLineTo(0f, -heightMinusCorners)
path.close() //Given close, last lineto can be removed.
return path
}