커스텀 뷰를 만드는 것은 어렵지 않다. 하지만 해당 뷰는 canvas를 사용해서 직접 원형 프로그래스바를 그리며, 이미지도 넣어야 하니 View를 상속받는 커스텀 뷰 클래스를 만들어보려고 한다.
class CustomView @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
): View(context, attributeSet, defStyleAttr) { ... }
모티부라는 앱 서비스는 부모가 함께 사용하는 서비스이기 때문에 여러 기기에서 사용된다는 가정을 세울 수 있었습니다. 그래서 다양한 해상도에서 대응되기 위해서 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 | 저밀도 화면, ~120dpi | 240 x 320px | 0.75 |
mdpi (표준) | 중밀도 화면, ~160dpi | 360 x 480px | 1 |
hdpi | 고밀도 화면, ~240dpi | 480 x 800px | 1.5 |
xhdpi | 초고밀도 화면, ~320dpi | 720 x 1280px | 2 |
xxhdpi | 초초고밀도 화면, ~480dpi | 1080 x 1920px | 3 |
xxxhdpi | 초초초고밀도 화면, ~640dpi | 1440 x 2560px | 4 |
디자인에서 해준 기본 뷰는 360x780 이다. 즉, canvas를 그릴 때, 우선적으로 해주어야 하는 부분이 있다. 그것은 뷰를 담는 레이아웃의 크기를 지정해야한다. 왜냐하면 XML에서 사용할 때, 간단하게 해당 View를 렌더링하면 되는 것이기 때문이다. 해당 부분은 뷰 생명주기 중 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가지 종류의 크기 모드를 확인할 수 있다.setMeasuredDimension(int measuredWidth, int measuredHeight)