Canvas를 사용한, 원형 프로그래스 바 제작기(2)

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

전개 1: 커스텀 뷰


커스텀 뷰를 만드는 것은 어렵지 않다. 하지만 해당 뷰는 canvas를 사용해서 직접 원형 프로그래스바를 그리며, 이미지도 넣어야 하니 View를 상속받는 커스텀 뷰 클래스를 만들어보려고 한다.

class CustomView @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
):  View(context, attributeSet, defStyleAttr) { ... }

다양한 기기의 대응하기 위환 Dp to Px


모티부라는 앱 서비스는 부모가 함께 사용하는 서비스이기 때문에 여러 기기에서 사용된다는 가정을 세울 수 있었습니다. 그래서 다양한 해상도에서 대응되기 위해서 Dp(Density-independent Pixel)를 Px(Pixel)로 변환하는 작업을 진행했습니다.

코드는 다음과 같습니다.

val Int.px: Float
    get() = this * Resources.getSystem().displayMetrics.density

💙 density 를 곱하는 이유는?
: 핸드폰의 크기는 다양하고 해당 해상도가 존재합니다. 안드로이드에서는 표준으로 160dpi를 기준으로 상대적 크기를 나타냅니다. 즉, 160dpi의 1dp = 1px 과 같다는 의미입니다.
여기서 잘 생각해야하는 부분은 디자이너들이 주는 피그마의 자료는 픽셀 단위로 이루어집니다. 그렇기 때문에 동적으로 뷰의 너비와 높이를 지정하려면 Dp를 Px로 변환해야하는 이유가 분명합니다.

픽셀로 변환하는 방법 : dp * 배율(density)

크기설명픽셀(가로x세로)배율(x)
ldpi저밀도 화면, ~120dpi240 x 320px0.75
mdpi (표준)중밀도 화면, ~160dpi360 x 480px1
hdpi고밀도 화면, ~240dpi480 x 800px1.5
xhdpi초고밀도 화면, ~320dpi720 x 1280px2
xxhdpi초초고밀도 화면, ~480dpi1080 x 1920px3
xxxhdpi초초초고밀도 화면, ~640dpi1440 x 2560px4

디자인에서 해준 기본 뷰는 360x780 이다. 즉, canvas를 그릴 때, 우선적으로 해주어야 하는 부분이 있다. 그것은 뷰를 담는 레이아웃의 크기를 지정해야한다. 왜냐하면 XML에서 사용할 때, 간단하게 해당 View를 렌더링하면 되는 것이기 때문이다. 해당 부분은 뷰 생명주기 중 onMeasure 에서 처리할 수 있다.

onMeasure로 뷰의 크기(너비와 높이) 설정하기


위 뷰의 너비와 높이를 설정할 수 있다. 코드는 다음과 같다.

💙 코드 설명
: 코드는 XML에 렌더링할 때, 뷰의 크기를 자체적으로 결정하게하기 위해서 wrap_content를 주었다. 그렇기 때문에 만약 뷰 크기 모드가 XML에서 특정 값을 설정했다면, 해당 값으로 뷰의 크기를 그린다. 하지만 그렇지 않다면 wrap_content라면, 내가 원하는 뷰의 너비와 높이(크기)를 설정할 수 있다.

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    if (measureMode(widthMeasureSpec) && measureMode(heightMeasureSpec)) {
        setMeasuredDimension(
            MeasureSpec.getMode(widthMeasureSpec),
            MeasureSpec.getMode(heightMeasureSpec)
        )
    } else {
        setMeasuredDimension(layoutSize, layoutSize)
    }
}

private fun measureMode(measureSpec: Int): Boolean =
        MeasureSpec.getMode(measureSpec) == MeasureSpec.EXACTLY
<com.android.motivoo.custom_view.CustomView
	...
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>
  • MeasureSpec.getMode(int measureSpec) : 3가지 종류의 크기 모드를 확인할 수 있다.
    • MeasureSpec.AT_MOST : 뷰 내부에서 자체적으로 뷰의 크기를 결정하라는 의미 (XML에서 wrap_content 시 적용된다.)
    • MeasureSpec.EXACTLY : XML에서 설정된 값으로 뷰의 크기가 설정된다. (특정 값, match_parent…)
    • MeasureSpec.UNSPECIFIED : 설정된 값 없음.
  • setMeasuredDimension(int measuredWidth, int measuredHeight)
    • 해당 메소드를 호출함으로써, 뷰의 크기를 원하는 만큼 설정할 수 있다.
profile
Allright!

0개의 댓글

관련 채용 정보