반응형
최근에 [점메추] 앱에서 메뉴를 추천하기 위한 방식중 하나로 개발을 했는데 아쉽게 실 버전엔 포함되지 못했습니다.
결과 화면
개발 방식
라이브러리도 있지만 커스텀하기 용이한 점과 개발 해보고 싶었던 마음이 있어 캔버스에 직접 그리는 방식으로 했습니다.
Roulette.kt
룰렛을 한 화면에서만 사용하지만 관리가 용이해 커스텀 뷰로 만들었습니다.
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas == null) return
val rectLeft = left + paddingLeft + Constant.DEFAULT_PADDING
val rectRight = right - paddingRight - Constant.DEFAULT_PADDING
val rectTop = height / 2f - rectRight / 2f + paddingTop + Constant.DEFAULT_PADDING
val rectBottom = height / 2f + rectRight / 2f - paddingRight - Constant.DEFAULT_PADDING
val rectF = RectF(rectLeft, rectTop, rectRight, rectBottom)
centerX = (rectF.left + rectF.right) / 2f
centerY = (rectF.top + rectF.bottom) / 2f
drawRoulette(canvas, rectF)
if (centerPointVisibility == VISIBLE) {
canvas.drawCircle(centerX, centerY, centerPointRadius, centerPointPaint)
}
}
rectF : 룰렛을 그려줄 공간
centerX, centerY : 룰렛 가운데 지점 좌표
fun drawRouleet
private fun drawRoulette(canvas: Canvas, rectF: RectF) {
if (rouletteDataList.size in 2..8) {
val sweepAngle = 360f / rouletteDataList.size.toFloat()
val radius = (rectF.right - rectF.left) / 2 * 0.5
for (i in rouletteDataList.indices) {
fillPaint.color = ContextCompat.getColor(context,shapeColors[i])
// draw roulette arc
val startAngle = if (i == 0) 0f else sweepAngle * i
canvas.drawArc(rectF, startAngle, sweepAngle, true, fillPaint)
// draw roulette text
val medianAngle = ((startAngle + sweepAngle / 2f) * Math.PI / 180f )
val x = (centerX + (radius * cos(medianAngle))).toFloat()
val y = (centerY + (radius * sin(medianAngle))).toFloat() + Constant.DEFAULT_PADDING
val text = rouletteDataList[i]
canvas.drawText(text, x, y, textPaint)
}
} else {
throw IndexOutOfBoundsException("size out of roulette")
}
}
- rouletteDataList : 룰렛에 표현된 메뉴 리스트
- sweepAngle : 원에서 한 메뉴들이 차지 하는 각도
위의 코드로 앞서 보여드린 룰렛 사진처럼 각 영역이 나뉘어지게 됩니다. 영역마다 글씨가 써집니다.
회전 함수
애니메이션을 활용해 구현하는게 제일 자연스러웠습니다.
/**
* 룰렛 회전 함수
* @param toDegrees : 종료 각도(시작 각도 : 0)
* */
private fun rotateRoulette(toDegrees: Float) {
val animListener = object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {}
override fun onAnimationStart(animation: Animation?) {
rotateListener?.onRotateStart()
}
override fun onAnimationEnd(animation: Animation?) {
rotateListener?.onRotateEnd(getRouletteRotateResult(toDegrees))
}
}
val rotateAnim = RotateAnimation(
0f, toDegrees,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
)
rotateAnim.duration = rotateDuration
rotateAnim.fillAfter = true
rotateAnim.setAnimationListener(animListener)
startAnimation(rotateAnim)
}
결과 영상
실제 앱엔 없지만 메뉴 추천 앱이 궁금하다면 링크를 클릭해주세요!
반응형
'안드로이드 > 레이아웃 구현과 활용' 카테고리의 다른 글
[Android] Slider를 활용한 가격 설정 적용기 (1) | 2024.03.19 |
---|---|
[AOS] 토스 하단 버튼 애니메이션 구현하기 (0) | 2022.03.02 |
[AOS] TextView에 Auto size 적용하기 (0) | 2021.11.10 |
[AOS] 무한 롤링 배너 구현 (0) | 2021.10.22 |
[And] 달력 만들기 - recyclerview 활용 (4) | 2021.04.20 |