원그래프 돌아가는 애니메이션 + 숫자 증가 애니메이션
가능 한 지 ..?
이미 있는 라이브러리를 쓰면 편하지만 디자인을 원하는대로 커스텀하기 힘들어서 직접 만드는 방법을 선택했다 (생각보다 얼마 안 걸림)
package com.example.sync_front
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.core.content.res.ResourcesCompat
class CircleGraphView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.STROKE
strokeWidth = 110f // 원의 선 두께
textSize = 56f // 텍스트 크기 설정
}
private var sweepAngles = FloatArray(4) // 각 섹션의 각도 저장 배열
init {
// 각 섹션에 애니메이션 추가
for (i in 0..3) {
animateSection(i, 0f, 0f) // 초기화할 때 모든 섹션을 0%로 설정
}
}
fun animateSection(section: Int, fromProgress: Float, toProgress: Float) {
if (section in 0..3) {
val animator = ValueAnimator.ofFloat(fromProgress, toProgress)
animator.duration = 1000 // 애니메이션 지속 시간을 1초로 설정
animator.interpolator = LinearInterpolator() // 애니메이션 간에 부드럽게 연결
animator.addUpdateListener { animation ->
sweepAngles[section] = 360 * (animation.animatedValue as Float / 100)
invalidate() // 뷰를 다시 그리도록 요청
}
animator.start()
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val radius = (Math.min(width, height) / 2).toFloat()
val rect = RectF(
width / 2 - radius + paint.strokeWidth / 2, height / 2 - radius + paint.strokeWidth / 2,
width / 2 + radius - paint.strokeWidth / 2, height / 2 + radius - paint.strokeWidth / 2
)
var startAngle = -90f
val sectionColors =
arrayOf(R.color.biscay_50, R.color.biscay_30, R.color.biscay_10, R.color.biscay_5)
val textColors =
arrayOf(R.color.white, R.color.biscay_70, R.color.biscay_50, R.color.biscay_30)
for (i in 0 until 4) {
paint.color = context.getColor(sectionColors[i])
canvas.drawArc(rect, startAngle, sweepAngles[i], false, paint)
val percentage = (sweepAngles[i] / 360 * 100).toInt()
if (percentage > 0) { // 0%가 아닐 경우에만 텍스트를 그립니다.
val sectionCenterAngle = startAngle + sweepAngles[i] / 2
val sectionCenterX = (width / 2 + (radius - paint.strokeWidth / 2) * Math.cos(
Math.toRadians(sectionCenterAngle.toDouble())
)).toFloat()
val sectionCenterY = (height / 2 + (radius - paint.strokeWidth / 2) * Math.sin(
Math.toRadians(sectionCenterAngle.toDouble())
)).toFloat()
val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = context.getColor(textColors[i])
textAlign = Paint.Align.CENTER
textSize = 40f
typeface = ResourcesCompat.getFont(context, R.font.spoqahansansneo_bold)
}
val text = "${percentage}%"
canvas.drawText(
text,
sectionCenterX,
sectionCenterY - (textPaint.descent() + textPaint.ascent()) / 2,
textPaint
)
}
startAngle += sweepAngles[i]
}
}
}
전체적인 코드는 이렇다
init 블록에서는 4개의 섹션(0~3) 각각에 대해 animateSection 함수를 호출하여 초기에 모든 섹션의 각도를 0%로 설정함
val sectionColors =
arrayOf(R.color.biscay_50, R.color.biscay_30, R.color.biscay_10, R.color.biscay_5)
val textColors =
arrayOf(R.color.white, R.color.biscay_70, R.color.biscay_50, R.color.biscay_30)
여기에는 디자이너가 준 컬러를 넣으면 된다.
<com.example.sync_front.CircleGraphView
android:id="@+id/circle"
android:layout_width="match_parent"
android:layout_height="150dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.example.앱이름.CircleGraphView>
를 원형 그래프 넣고 싶은 부분에 추가한다.
package com.example.sync_front.sync
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.sync_front.CircleGraphView
import com.example.sync_front.databinding.ActivitySyncBinding
class SyncActivity : AppCompatActivity() {
private lateinit var binding: ActivitySyncBinding
private lateinit var circleGraphView: CircleGraphView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySyncBinding.inflate(layoutInflater)
setContentView(binding.root)
setupCirCleGraphView()
}
private fun setupCirCleGraphView() {
circleGraphView = binding.circle
circleGraphView.animateSection(0, 0f, 25f) // 첫 번째 섹션을 0%에서 25%로 애니메이션 적용
circleGraphView.animateSection(1, 0f, 25f) // 두 번째 섹션을 0%에서 50%로 애니메이션 적용
circleGraphView.animateSection(2, 0f, 25f) // 세 번째 섹션을 0%에서 75%로 애니메이션 적용
circleGraphView.animateSection(3, 0f, 25f) // 네 번째 섹션을 0%에서 100%로 애니메이션 적용
}
}
일단 임시로 하드코딩 했는데 .. 파라미터 함수를 만들어주면 더 깔끔한 코드가 될 거 같다
저렇게 하면!!
이제 디자이너가 준 대로 원형 그래프에 애니메이션까지 넣을 수 있게 되었다! 야호 ~~