목적
Compose의 Canvas를 이용해서 View Pager와 같이 쓸 Dot Indicator 만들기.
요구사항
R_1. 이 인디케이터는 modifier.align 을 통해 센터 정렬을 한다.
R_2. dot은 기본으로 원형이다. 현재 페이지를 나타내는 dot은 가로로 길쭉하게 늘어져 있는 라운드처리된 직사각형이다.
코드 / 구현
@Composable
fun BoxScope.DotIndicator(
modifier: Modifier = Modifier,
pagerState: PagerState,
dotSpace: Dp = 4.dp,
dotSize : Dp = 5.dp,
currentDotWidth : Dp = 12.dp,
listSize: Int,
currentPageDotColor: Color = Mycolor.gray,
totalPageDotColor: Color = Mycolor.point
) {
val totalWidth = (dotSize + dotSpace).times(listSize - 1) + currentDotWidth
var offsetX = -totalWidth / 2f
Canvas(modifier = modifier.width(
totalWidth
).height(dotSize).wrapContentWidth(),
onDraw = {
for (index in 0 until listSize) {
if (index == pagerState.currentPage) {
drawRoundRect(
color = currentPageDotColor,
topLeft = Offset(x = offsetX.toPx(), y = 0f),
cornerRadius = CornerRadius(20.dp.toPx()),
size = Size(width = currentDotWidth.toPx(), height = dotSize.toPx())
)
offsetX += currentDotWidth
} else {
drawCircle(
radius = dotSize.toPx() / 2f,
color = totalPageDotColor,
center = Offset(x = offsetX.toPx() + 2.5.dp.toPx(), y = dotSize.toPx() / 2f),
)
offsetX += dotSize
}
if (index < listSize - 1) {
offsetX += dotSpace
}
}
offsetX = -totalWidth / 2f
})
}
고려 사항
1. Canvas의 가로 사이즈를 지정해줘야 한다.
R_1을 위해서 가로 사이즈를 지정해줘야 했다.
코드를 보면 Canvas의 가로 사이즈를 계산해서 넣어주고 있다.
Canvas 함수를 살펴보니 Spacer에 drawBehind로 DrawScope가 제공된다. 확인해보니 Spacer의 영역과 상관없이, 영역을 넘어서도 onDraw 안에 원하는 바를 그릴 수 있으나 Spacer의 영역으로는 인정하지 않았다. 내가 width를 지정하지 않으면, Canvas Composable의 시작점을 중심으로 센터 정렬을 시켰다. 그래서 dot의 길이와 개수에 따라 계산해서 canvas의 width 값을 지정하니 원하는 대로 센터 정렬이 가능했다.
2. drawRect의 topLeft 값 설정과 drawCircle의 center 값 설정으로 dot들의 정렬 맞추기
R_2에 따라 현재 선택된 화면의 dot은 drawRect로 그리고, 그 외의 dot은 drawCircle로 그렸다.
그런데 drawRect와 drawCircle가 위치를 잡는 기준점이 달랐다.
drawRect는 topLeft로, 상단 왼쪽의 값을 지정해야 하고, drawCircle은 정 가운데 위치를 잡아줘야 했다.
dot의 크기 값들로 해당 drawRect의 topLeft, drawCircle의 center 값을 구했다.
topLeft와 center의 타입은 Offset이다. 이 Offset.Zero 값이 무엇인가 봤더니, 좌표 한가운데 (0,0)이었다.
첫 번째 dot의 x좌표 위치는 마이너스 값이어야 한다는 것도 알았다.
이 정도면 나름 계산하고 구현하기 쉽고 재미있었다.
'곳간에서 인심난다 > 실무' 카테고리의 다른 글
[Android][TextView] marquee 설정 (0) | 2023.10.28 |
---|---|
[Android][Java] 초성 검색 (0) | 2023.10.28 |
[Android][DataStore] DataStore 동기적으로 쓰기 (0) | 2023.10.08 |
[Android]앱 빌드 설정 - zero base 프로젝트 개발 시 내용 정리의 필요성을 느낀 것들 (0) | 2023.10.03 |
[Android][Compose][삽질 교훈] Compose Migration + Expandable List (0) | 2023.02.23 |