Android

[Android] density? dp와 px

한때미 2026. 10. 9. 13:02

 

Android 16 대응을 하면서 configuration에 대해 알아보다 "density" 값에 대해 좀 더 알아볼 필요를 느껴 정리하게 되었다.

해당 옵션 값은 우선 화면 밀도가 변할 때 적용되는 값으로, 폴드를 접은 상태에서 펼칠 때 등의 상황에 변경될 수 있다.

 

 


density

화면 밀도, 좀 더 정확히 말하자면 1dp를 몇 px로 그릴지를 정하는 배율 숫자이다.

 

dp는 160dpi(mdpi) 화면의 1px을 기준으로 한 가상 단위이며, 실제 px는 현재 density 배율을 곱해 계산된다.

  • dpi(densityDpi): 화면의 밀도 값. 실제 물리 밀도가 아니라 시스템이 정한 논리 밀도다.
  • density(DisplayMetrics.density): dp를 px로 바꾸는 배율. mdpi에서 1.0, hdpi에서 1.5, xhdpi에서 2.0이다.
공식 문서는 위 공식을 코드에 직접 쓰지 말고 TypedValue.applyDimension()을 쓰도록 안내한다. ViewConfiguration의 getScaled* 메서드처럼 이미 변환된 값을 주는 API도 있다.

 

// 공식 문서 예시: dp → px
val gestureThreshold = TypedValue.applyDimension(
    COMPLEX_UNIT_DIP,
    GESTURE_THRESHOLD_DP + 0.5f,
    resources.displayMetrics
).toInt()

 

 

px

화면의 물리적인 점 하나,

"1080×2400 화면"이라고 하면 가로 1080개, 세로 2400개의 점이 있다는 뜻.

 

같은 크기의 화면이라도 점의 촘촘함이 기기마다 다르다.

100px 버튼은 성긴 화면에서는 크게, 촘촘한 화면에서는 작게 보일 수 있다.

 

dpi

1인치에 점이 몇 개 들어가는지를 나타낸다.

값이 클수록 화면이 촘촘하다.

 

dp

160dpi 화면(1인치 안에 160px이 존재)의 1px을 1dp로 정한 기준 단위. 실제 크기로는 약 1/160인치.

촘촘한 화면일수록 1dp에 더 많은 px를 써서(dp의 실제 인치에 맞춰서 px 소비), 어느 기기에서든 비슷한 실제 크기로 보이게 한다.

 

예: 48dp 버튼은 160 dpi 화면에서 48px, 480 dpi 화면에서 144px이다. 두 화면 모두 실제 크기는 약 0.3인치.

그렇기 때문에 레이아웃은 dp로 쓰고, px 변환은 시스템이 density 배율로 처리한다.

 

구분 무엇인가 예시
px 단위. 화면의 실제 점 1개 1px
해상도 화면 전체를 px로 잰 값 가로 1080px × 세로 2400px
dp 단위. 160dpi 기준의 가상 픽셀 1개 1dp

 

 

화면 1인치 안의 px 1dp = 몇 px 1인치 = 몇 dp
160dpi 160px 1px 160dp
320dpi 320px 2px 160dp
480dpi 480px 3px 160dp

 


밀도 한정자 (density qualifier)

drawable-xhdpi/처럼 리소스 폴더 이름 뒤에 붙여 어느 밀도 화면용 리소스인지 표시한다. 앱 실행 시 시스템이 기기의 densityDpi에 가장 맞는 폴더를 고른다.

한정자 dpi(대상 밀도) 배율 48dp 아이콘 의미
ldpi ~120dpi 0.75x 36px 저밀도. 현재는 거의 쓰이지 않음
mdpi ~160dpi 1.0x 48px 기준 밀도 (1dp = 1px)
tvdpi ~213dpi 1.33x 약 64px mdpi와 hdpi 사이. 주요 버킷은 아님
hdpi ~240dpi 1.5x 72px 고밀도
xhdpi ~320dpi 2.0x 96px 초고밀도
xxhdpi ~480dpi 3.0x 144px 최근 폰에서 흔한 밀도
xxxhdpi ~640dpi 4.0x 192px 런처 아이콘 등에 사용
nodpi 전체 — 원본 크기 밀도와 관계없이 스케일하지 않음
anydpi 전체 — 벡터로 렌더링 벡터처럼 모든 밀도에 쓰는 리소스. 다른 밀도 폴더보다 우선함

 

  • 주요 6개 밀도는 3:4:6:8:12:16 비율을 따른다.
  • 딜 맞는 폴더가 없으면 가까운 밀도의 리소스를 확대·축소해 쓴다. 예를 들어 420 dpi 기기는 보통 xxhdpi(480) 리소스를 축소해 쓴다.
  • 낮은 밀도의 비트맵을 확대하면 흐려질 수 있어, 비트맵은 여러 밀도로 준비하거나 벡터 드로어블을 쓰는 것이 권장된다.
    (Support different pixel densities)

 


💡 sp와 fontScale

폰트, 글자 크기의 단위 sp.

 

sp는 기본적으로 dp와 같은 크기지만 사용자의 글자 크기 설정(fontScale)을 따라 커지는 단위이며,

Android 14부터는 단순 곱셈이 아닌 비선형 곡선으로 계산된다.

(글꼴 크기 설정이 기본값(100%)이면 sp와 dp는 크기가 똑같다)

 

sp는 텍스트 크기에만 쓰고 레이아웃 크기에는 쓰지 않는다.

 

density와 fontScale은 별개의 Configuration 항목이다.

"화면 크기(Display size)" 설정은 density를, "글꼴 크기(Font size)" 설정은 fontScale을 바꾼다.

 

Android 14는 최대 200%까지 글자 확대를 지원하고, 큰 글자는 작은 글자보다 덜 커지도록 비선형으로 스케일 한다.

그래서 4sp + 20sp가 24sp와 같지 않을 수 있다. padding이나 높이를 sp로 계산하면 비율이 깨질 수 있다.

 

lineHeight는 textSize와 함께 sp로 지정해야 TextView가 비율을 보정해 준다.

 

 

sp ↔ px 변환

val metrics = resources.displayMetrics
val textPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16f, metrics)
val textSp = TypedValue.deriveDimension(TypedValue.COMPLEX_UNIT_SP, textPx, metrics)

TypedValue.applyDimension()(sp → px)과 TypedValue.deriveDimension()(px → sp)을 쓰면 비선형 곡선이 자동 적용된다.

테스트는 설정 > 접근성 > 디스플레이 크기 및 텍스트에서 글꼴 크기를 최대(200%)로 올려 확인할 수 있다. (Android 14 features)

 

이제 sp는 비선형 곡형으로 계산되기 때문에 Configuration.fontScale이나 DisplayMetrics.scaledDensity로 직접 계산하지 말라고 안내한다.

scaledDensity는 더 이상 정확하지 않고, fontScale은 참고용으로만 써야 한다.

 


density가 런타임에 바뀌는 상황

공식 문서는 density 변경을 "사용자가 다른 디스플레이 배율을 지정하거나, 다른 디스플레이가 활성화된 경우"로 설명한다.

 

상황 함께 바뀔 수 있는 값
설정에서 "화면 크기(Display size)" 변경 density, screenSize, smallestScreenSize, screenLayout
폴더블 내부/외부 화면 전환 density, screenSize, smallestScreenSize, screenLayout
외부 디스플레이로 창 이동 (데스크톱 모드 등) density, smallestScreenSize, screenLayout
설정에서 "글꼴 크기" 변경 fontScale (density는 바뀌지 않음)

 

화면 크기 설정을 바꾸면 dp 기준 화면 너비도 함께 바뀌므로, density 단독으로만 바뀌는 경우는 드물다.

그래서 만약 configChanges를 사용하여 Activity 재생성을 방지하기 위해 density만 선언하면 함께 바뀐 다른 항목 때문에 결국 재생성될 수 있다. Configuration 변경은 선언하지 않은 항목이 하나라도 바뀌면 재생성되기 때문이다.

 

 

ADB 명령어로도 직접 변경하여 확인할 수 있다.

# 현재 값 확인
adb shell wm density
# Physical density: 420   ← 기기 기본값
# Override density: 480   ← 바꾼 값 (바꾼 적이 있을 때만 표시)

# density 변경
adb shell wm density 480

# 원래 값으로 복구
adb shell wm density reset

 

 

 

 


추가 학습 거리

  • configChanges 옵션, 동작
  • View(XML)와 Compose의 반영 방식
  • Compose Dialog와 density

 

 

참고 자료

더보기