Canvas를 사용한, 원형 프로그래스 바 제작기(6) - 마지막

조관희·2024년 3월 4일
0
post-thumbnail

전개 5: 원형 프로그래스 바와 같이 자녀와 부모 아이콘 이미지를 어떻게 움직이게하지?


이제 가장 중요한 부분입니다. 원형 프로그래스 바가 증가할 때, 그 증가에 따라서 이미지도 이동해야 합니다. 이 과정을 고민할 때는 크게 리소스를 사용하지 않았습니다. 간단하게 원의 테두리 좌표를 구하면 되지 않을까 생각하면 삼각함수를 꺼내서 진행했습니다.

원 테두리 좌표 구하기


  • 참고 자료

원의 좌표를 구하는 공식을 활용한 애니메이션 :: 마이구미

미리 알고 있어야 하는 값들이 존재합니다.

  • 각도 (θ)
  • 반지름 (r)

반지름과 각도만 안다면 원 테두리의 좌표는 쉽게 구할 수 있습니다. 우선 x 좌표를 구하는 공식을 알아봅시다.

  • x 좌표 구하기

  • y 좌표 구하기

다음과 같이 구하게 되면 원 테두리의 좌표는 다음과 같은 공식이 나옵니다.

  • x 좌표 = cos(θ) x r
  • y 좌표 = sin(θ) x r

이제 이것을 응용하여 이미지를 원형 프로그래스 바에 접근하게 하도록 해보겠습니다.

좌표에 이미지 넣어보기


  • 라디안 공식 알아보기

삼각함수를 사용해서 좌표를 가져오기 때문에 라디안이라는 것이 무엇인지 다시 알아보자.

호도법(Radian)

  • 계산하기
    • 원하는 각도에서 30도를 뺀 값을 기준으로 분기 처리해주어야 합니다.
    • (1) 과 (2) 의 방법으로 좌표를 구해야 합니다. (2) 방법같은 경우에는 y 값이 증가하는 것을 알 수 있습니다.
    • 다음과 같은 공식으로 (1) 번 방법의 (x, y) 좌표와 (2) 번 방법의 (x, y) 좌표를 얻을 수 있습니다.

1번 방법)

  • x = 뷰 너비의 반 - cos(라디안) * 반지름
     **= 180 (pixel) - cos(radian) * 140 (pixel)**
  • y = 뷰 높이의 반 - sin(라디안) * 반지름
     **= 180 (pixel) - sin(radian) * 140 (pixel)**

2번 방법)

  • x = 뷰 너비의 반 - cos(라디안) * 반지름
     **= 180 (pixel) - cos(radian) * 140 (pixel)**
  • y = 뷰 높이의 반 + sin(라디안) * 반지름
     **= 180 (pixel) + sin(radian) * 140 (pixel)**

그런데 이미지를 보니 조금 이상합니다. 안쪽으로 밀려난 이미지가 나타나는 것을 알 수 있습니다. 이러한 문제점은 canvas의 원리를 이해하면 쉽습니다. 좌표를 기준으로 아래와 오른쪽으로 그림을 그리게 되는데, 그렇게 되면 당연하게 영상처럼 안쪽으로 이미지를 그리게 됩니다. 그렇기 때문에 이미지의 크기인 너비와 높이를 알아서 너비를 x 좌표 값에서 빼고, 높이를 y 좌표 값에서 뺀다면 왼쪽 위로 이미지를 올릴 수 있습니다. 즉, 원 테두리 좌표에 정확하게 넣을 수 있는 것 입니다.

1번 방법)

  • x = 뷰 너비의 반 - cos(라디안) * 반지름 - 이미지 너비의 반
     **= 180 (pixel) - cos(radian) * 140 (pixel) - 24.px**
  • y = 뷰 높이의 반 - sin(라디안) * 반지름 - 이미지 높이의 반
     **= 180 (pixel) - sin(radian) * 140 (pixel) - 24.px**

2번 방법)

  • x = 뷰 너비의 반 - cos(라디안) * 반지름 - 이미지 너비의 반
     **= 180 (pixel) - cos(radian) * 140 (pixel) - 24.px**
  • y = 뷰 높이의 반 + sin(라디안) * 반지름 - 이미지 높이의 반
     **= 180 (pixel) + sin(radian) * 140 (pixel) - 24.px**

코드로 알아보면 다음과 같습니다. percent 값이 증가함으로써, degree 값이 변경되어지고, setImageBitmap 메서드가 호출됨으로써 이미지를 다시 그리게 되는 것입니다.

private var percent = 0F
private var degree = 0.0
private var imageBitmap: Bitmap? = null
private var x: Double = 0.0
private var y: Double = 0.0

override fun onDraw(canvas: Canvas) {
  super.onDraw(canvas)
	...

  imageBitmap?.let {
      canvas.drawBitmap(it, x.toFloat(), y.toFloat(), null)
  }
}

fun setPercent(percent: Float) {
  this.percent = percent
  degree = (percent * 120.0)
  invalidate()
}

fun setImageBitmap(@DrawableRes image: Int) {
  var radian: Double

  radian = if (degree - 30 < 0) { // 1번 방법
      Math.toRadians(30.0 - degree)
  } else { // 2번 방법
      Math.toRadians(degree - 30.0)
  }

  x = 180.px - cos(radian) * 140.px - 24.px
  y = if (degree - 30 < 0) { // 1번 방법
      180.px + sin(radian) * 140.px - 24.px
  } else { // 2번 방법
      180.px - sin(radian) * 140.px - 24.px
  }

  imageBitmap = ContextCompat.getDrawable(context, image)?.run {
      toBitmap(48.px.toInt(), 48.px.toInt())
  }
  invalidate()
}

이러한 방법과 똑같이 반대쪽도 진행한다면 진행했던 “모티부” 서비스의 원형 프로그래스 바 커스텀 뷰 작성을 완성하게 된다.

결론


디자인이 나왔을 때, 당황을 했다. 처음보는 프로그래스 바 디자인이었고, 커스텀 뷰를 해봤지만 canvas를 사용하여 흰 도화지에 그림 그려본 적은 없었기 때문이다. 잘해낼 수 있을까.. 고민을 많이 했지만, 나는 디자인이 해당 디자인을 할 수 있냐고 물어봤을 때, 당시에는 고민하지도 않고 “네 할 수 있습니다.” 라고 답했다. 자신 있었다. 할 수 있을 것 같은 자신감이 그 순간에는 계속 들었다. 실제로 진행하면서 좌우반전, 이미지 canvas로 그리기, 이미지 움직이기 등 다양한 문제를 직면했지만 계속해서 고민하고 레퍼런스를 찾아보면서 해결할 수 있었다.
개발에 있어서 걸림돌이 되는 것은 실력인 것 같다. 지금도 많이 부족한 원형 프로그래스 바라고 생각한다. 만약에 실력이 더 출중했다면, 디자인 요구에 맞는 완벽한 원형 프로그래스 바를 만들 수 있을 것 같았다. 그래도 이번 원형 프로그래스 바를 제작하면서 느낀점은 해보지 않고 포기하려는 것은 실패하는 것보다 참담하다고 생각한다. 실패를 겪고 그 문제점을 고민해보는 것이 개발자라면 항상해야하는 고민이라고 생각한다. 이번 “모티부”라는 서비스를 만들면서 한 단계 성장할 수 있는 경험이여서 좋은 경험이었다.

profile
Allright!

0개의 댓글

관련 채용 정보