안드로이드 개발자가 놓치기 쉬운 UX (feat. 피츠의 법칙)

@onseok· March 04, 2025 · 12 min read

안드로이드 앱을 개발하다 보면 UI는 완벽해 보여도(적어도 프로덕트 디자이너분들께서 요구하는 사항들을 전부 만족하더라도?), 사용자 경험(UX) 측면에서 사소하지만 치명적인 요소들을 간과하기 쉽습니다. 특히 피츠의 법칙(Fitts’ Law)을 이해하면 버튼 터치 영역, 제스처 동작 등에서 흔히 놓치는 UX 포인트를 개선할 수 있습니다. 이번 글에서는 피츠의 법칙 개념부터 시작해, 안드로이드 개발자가 챙겨야 할 UX 요소들과 실제 개선 방법을 살펴보겠습니다.

피츠의 법칙?

fitts law

피츠의 법칙은 간단히 말해 “목표(target)까지의 거리(D)가 멀수록, 그리고 목표 크기(W)가 작을수록 도달(클릭/터치) 시간이 늘어난다”는 인간 동작 모델입니다. 원래는 마우스 커서 같은 포인터 이동에 대한 연구였지만, 터치스크린 환경에도 그대로 응용됩니다. 사용자가 화면에서 버튼을 누를 때 걸리는 시간은 버튼의 크기와 현재 손가락 위치로부터의 거리에 영향을 받습니다.

fitts law 2

클릭/터치 시간 T는 거리(D)와 크기(W)의 함수로 나타낼 수 있습니다. 예를 들어 Target A와 B의 크기가 동일하다면, 손가락/포인터에서 가까운 A를 더 빨리 누를 수 있고, Target C처럼 크기가 작은 경우 가까이 있어도 시간이 더 걸립니다.

모바일에서는 피츠의 법칙이 더욱 중요합니다. 손가락이 직접 화면을 터치하는 방식이기 때문인데, 마우스 포인터는 화면의 작은 영역도 정확히 가리킬 수 있지만, 손가락은 크기도 크고 터치할 때 화면을 가려서 정교함이 떨어집니다. 실제로도 제 엄지손가락이 남들보다 굵은 편이라 터치할 때 버튼이 작으면 터치하기가 불편했던 경험이 많았습니다. 다시 말해, 터치는 마우스보다 정밀도가 낮은 입력 수단입니다. 따라서 안드로이드 UI를 개발할 때 터치 대상은 충분히 크게, 그리고 조작 영역에서 너무 멀리 떨어져 있지 않게 배치하는 것을 고려하는 것이 좋습니다. 피츠의 법칙에 따르면 작은 버튼이나 구석진 위치의 메뉴는 사용자가 누르기 어렵고 시간도 더 걸리므로, UX를 해치게 됩니다.

또 한 가지, 터치 목표 사이의 간격도 고려해야 합니다. 버튼들이 너무 촘촘하거나 작으면 사용자는 원하는 대상을 누르기 힘들고, 잘못 눌러 오동작(잘못된 대상 터치)할 확률이 높아집니다. 이는 사용자가 인터페이스를 불편하게 느끼게 만드는 요인이 됩니다.

개발에는 어떻게 적용해볼까?

Android UI를 개발할 때, 클릭 리스너(OnClickListener)를 UI 요소의 특정 뷰에만 걸어두고, 정작 사용자가 누를 수 있는 실제 영역은 아주 좁게 남아있는 경우가 흔합니다. 예를 들어 리스트 아이템 전체를 눌러야 할 것 같지만, 개발자가 아이콘이나 텍스트 뷰에만 리스너를 달면 사용자는 빈 공간을 눌렀을 때 반응이 없어 당황하게 됩니다. 이는 피츠의 법칙 측면에서 보면 목표 영역이 불필요하게 작아진 사례입니다.

이런 문제는 터치 영역을 확장함으로써 해결할 수 있습니다. 안드로이드 Material Design 가이드라인에서도 “아이콘이 24dp로 보여도 주변 패딩을 합쳐 실제 터치 영역은 48x48dp로 만들어야 한다”고 권장합니다. 또한 android:padding이나 TouchDelegate 등을 활용해 버튼 주위의 투명한 공간도 클릭을 감지하도록 개발하는 방법도 있습니다. 전체 레이아웃을 클릭 가능하게 옵션을 주거나, 터치 영역을 넓히는 것도 방법이 될 수 있습니다.

햅틱 피드백(Haptic Feedback)도 있다

앱을 사용하다 보면 진동 피드백을 통해 눌림이나 동작 완료를 느낄 때가 있습니다. 바로 햅틱 피드백인데요, 저는 이전에 창업을 하여 Preat이라는 서비스를 개발할 때, 이를 구현했었던 경험이 있습니다. 그런데 간혹가다가 기능 구현에 몰두하다 보면 이러한 햅틱 피드백을 잊는 경우도 많습니다. 가령 롱프레스(길게 누르기) 동작이나 드래그 앤 드롭, 또는 스와이프 제스처 등에서 짧은 진동을 주면 사용자는 “지금 동작이 인식됐구나”를 직감적으로 알 수 있습니다.

안드로이드에서는 Vibrator 클래스를 통해 쉽게 햅틱을 구현할 수 있습니다.

Column(
    modifier = Modifier.fillMaxSize(),
    horizontalAlignment = Alignment.CenterHorizontally,
    verticalArrangement = Arrangement.Center
) {
    // Vibration Controller
    val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

    // Vibration Button - OneShot
    Button(onClick = {
        // Safely cancel any ongoing vibrations
        vibrator.cancel()

        // Handling vibrations for Android 8.0 (Oreo) and above
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val effect = VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)
            vibrator.vibrate(effect)
        } else {
            // Handling vibrations for devices below Android 8.0
            vibrator.vibrate(100)
        }
    }) {
        Text(text = "Vibration Button OneShot")
    }

    // Vibration Button - Predefined Effect (Android 10 or above)
    Button(onClick = {
        // Safely cancel any ongoing vibrations
        vibrator.cancel()

        // Checking for Android 10 or above
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
            vibrator.vibrate(effect)
        } else {
            // Handling vibrations for devices below Android 10
            vibrator.vibrate(100)
        }
    }) {
        Text(text = "Vibration Button Predefined")
    }
}

개인적으로 진동을 너무 잦게 혹은 강하게 주면 오히려 거슬리다고 느낀 경험이 있어, 상황에 맞는 패턴과 세기를 선택하는 것이 중요할 것 같습니다.

Android Predictive Back API는 또 뭔데?

안드로이드 13부터 도입된 Predictive Back 제스처(예측성 뒤로 가기)는 UX 향상을 위한 새로운 시스템 기능입니다. Predictive Back을 적용하면 사용자가 뒤로 스와이프 제스처를 시작하는 순간 다음 화면을 미리 보여주는 애니메이션이 나타납니다. 이를 통해 사용자는 이 제스처를 계속 하면 어디로 갈지 미리 확인하고 결정할 수 있게 됩니다.

Android 15부터는 개발자 옵션 설정 없이 디폴트로 볼 수 있고, AndroidX Activity 1.6.0-alpha05 이후의 버전으로 업데이트하고, Manifest파일의 application 태그에 android:enableOnBackInvokedCallback=“true”를 적용하면 시스템이 뒤로 가기 제스처를 미리 알고 애니메이션을 처리할 수 있게 됩니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    ...
    <application
        ...
        android:enableOnBackInvokedCallback="true">
        ...
    </application>

</manifest>

만약 android:enableOnBackInvokedCallback 플래그를 false로 설정해두면, 시스템은 OnBackInvokedCallback 구현부에서 호출하는 동작을 모두 무시하게 됩니다. 대신 여전히 하위 호환성을 위해 기존의 onBackPressed API를 호출하므로, OnBackPressedCallback은 계속 정상적으로 동작하게 됩니다.

만약 유저의 Back 제스처로 곧바로 이전 화면을 보여주고 싶지 않을 때(예를 들어, 유저에게 정말로 뒤로가고 싶은지 물어보는 다이얼로그를 노출하고 싶을 때)에는 아래와 같이 구현하면 됩니다.

private val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
        //your custom onBackPressed logic
        showConfirmationDialog()
    }
}

그리고, 이 callback을 OnBackPressedDispatcher에 추가하면 끝입니다.

onBackPressedDispatcher.addCallback(onBackPressedCallback)

더 자세히 적용해보고 싶다면, 아래 코드랩 링크들을 참고하면 도움이 될 것 같습니다.

결론

지금까지 피츠의 법칙을 중심으로 설명한 UX 요소들은 개선은 결국 사용자를 위한 배려라고 볼 수 있습니다. 버튼의 터치 영역을 넓히고, 손가락이 닿는 범위를 고려해 배치하는 등 개발 단계에서 조금만 신경 쓰면 사용자 불편을 크게 줄일 수 있다고 생각합니다.

특히 안드로이드 앱은 다양한 기기 화면 크기와 사용 환경에서 실행되므로, 보편적인 UX 원칙을 지키는 것이 중요합니다. 이렇게 개발자가 UX를 먼저 고려한다면 기획 단계에서부터 완성도 높은 서비스를 만들 수 있고, 회사에서 기획자나 디자이너와의 의사소통도 원활해질 수 있을 것이라고 생각합니다. 특히 저도 자주 놓치는 부분이기는 하지만, 안드로이드 개발자로서 UI 개발을 하다보면 과연 내가 Material Design이나 안드로이드 접근성 가이드 등 권장사항을 따르고 있는가? 라고 끊임없이 되묻는 자세가 필요한 것 같습니다.

작은 버튼 하나, 진동 한 번의 차이가 모여 앱의 성공을 결정짓는 UX를 만들 수 있다는 점을 믿으며, 놓치기 쉬운 UX 요소들을 챙기는 습관이 AI 시대의 프로덕트 엔지니어로서 곧 사용자의 행복을 만들 수 있다고 생각합니다.

참고 자료

@onseok
배움을 배포하기