[안드로이드 UI최적화] 나인패치의 모든것


안드로이드의 나인패치는 다양한 단말에 최적의 UI를 구성하기 위해 가장 필수적인 항목으로 .9.png 확장자를 가진 이미지 파일로 반복되는 영역과 패딩 영역을 이미지에 정의할 수 있다. 안드로이드 UI구성시 화면의 해상도가 다양하기 때문에 화면에 맞는 최적의 이미지를 각각 가지고 있는 것 보다 나인패치 된 이미지를 사용하는 것이 훨씬 유리하다. 나인패치를 이용하게 되면 하나의 이미지를 통해 다양한 해상도에서 최적의 UI를 구성할 수 있다.

 

나인패치 파일은 .png이미지에 1픽셀로 된 검은색((#000000) 테두리를 통해 인식이 된다. 왼쪽과 상단부분은 늘어나는 영역을 지정하게되며 겹치는 부분이 반복적으로 늘어나게된다. 오른쪽과 하단부분은 패딩부분으로 나인패치한 부분내에 컨텐츠가 들어가는 경우 정렬되는 범위이다.
1.7.2

<그림 1.7.2> 나인패치 구조

나인패치된 이미지는 아무리 늘려도 강제로 늘린 것 처럼 깨져보이는 것이 아닌 원본을 유지한 상태로 늘어나게 된다. 아래처럼 나인패치된 이미지를 늘리게 되면 늘어나는 영역의 부분이 패턴식으로 반복되어 표현되기 때문에 원본의 이미지를 유지하는 것 처럼 보인다.

 

1.7.3-1

원본 이미지

1.7.3-2강제로 늘린이미지

1.7.3-3

나인패치를 통해 늘린이미지

<그림 1.7.3> 나인패치된 이미지와 강제로 늘린이미지 비교

 

나인패치된 이미지에 텍스트나 이미지등의 콘텐츠가 들어가기 위한 배경으로 사용되는 경우 콘텐츠의 패딩영역을 지정 할 수 있다. 오른쪽과 하단부분의 중복된 영역이 패딩영역으로 이 부분에 콘텐츠가 들어가게된다.
1.7.4

<그림 1.7.4> 나인패치 패딩영역

 

나인패치를 이용하면 작은 이미지 리소스로 다양한 크기의 이미지를 깨짐없이 표현 할 수 있는 장점이 있다. 다양한 해상도를 가지는 안드로이드 단말에서 없어서는 안 될 좋은 시스템이다. 하지만 나인패치 영역을 반복적인 패턴으로 보여주기 때문에 패치역역의 첫 부분과 끝 부분이 같아야 자연스럽게 표현이 된다. 반복되는 패턴이 아닌 질감을 가지는 이미지일 경우 나인패치를 사용하기는 힘들다.

 

1.7.5-1

1.7.5-3

나인패치 이미지

1.7.5-2

1.7.5-4

나인패치된 이미지 사용

<그림 1.7.5> 질감을 가진 이미지의 나인패치

 

 

이미지 스케링에 대한 팁

 

안드로이드에서는 이미지를 자동으로 스케일링 하게 되는데, hdpi를 기준으로 나인패치를 만들었는데 xhdpi단말기에서 실행하게 되면 이미지 크기를 늘리게 된다. 이렇게 스케일링 과정 중 이미지 영역은 스케일링 되며 나인패치 영역은 스케일링이 되지 않아 설정된 나인패치 영역이 원하는 부분에 잡히지 않을 수 있다.

그림 1.7.6의 왼쪽 이미지는 스케일링 과정에 문제점이 발생된다. 상단의 늘어나는 부분의 영역과 늘어나지 않는 영역의 디자인이 명확하게 나누기 위해 나인패치 영역을 잡은 것을 볼 수 있다. 이렇게 너무 명확하게 나눠 버리는 경우 이미지가 스케일링 되면서 의도한 나인패치의 영역이 명확하게 나누기 위한 영역이 아니게 바뀌게 될 수 있다. 이와 마찬가지로 왼쪽의 늘어나는 부분을 1픽셀로 잡혀 있는데 스케일링 과정에 나인패치의 영역이 없어져 버릴 수도 있다. 그림 1.7.6의 오른쪽 이미지는 이런 스케일링의 문제점을 해결 하기 위해 상단의 늘어나는 부분은 디자인이 바뀌는 영역을 조금 피해 여유분을 주었으며, 왼쪽의 늘어나는 부분의 영역을 좀 더 크게 잡아 주었다.

 

1.7.6-1

스케일링으로 인해 문제가 있는 나인패치

1.7.6-2

스케일링에 대한 처리가 된 나인패치

 

<그림 1.7.6> 나인패치 DPI 스케일링 팁

 

  • 늘어나는 영역은 최소 2~4픽셀로 한다.
  • 늘어나는 영역 외 충분 한 영역을 준다.

 

 

나인패치 예제

 

나인패치는 버튼, 입력필드, 배경등으로 다양하게 활용 할 수 있다. 버튼의 경우 다양한 크기의 가진 버튼을 하나의 나인패치로 대응이 가능하여 어떠한 기기에서도 UI를 구성할 수 있기 때문에 나인 패치는 필수이다. 또한 리스트의 아이템의 배경으로도 많이 사용되며 다양하게 응용가능하다. 좀 더 다양항 예제를 통해 어떻게 사용하며 응용할지 알아보자.

예제1. 입력필드

입력필드에서 이미지의 가로만 늘어 나고 세로부분의 이미지는 고정되어 있어야 하는 경우 다음과 같이 나인패치가 가능하다. 그림 1.7.7은 세로로 이미지는 늘어 나지 않아야 하기 때문에 이미지의 빈 영역에 나인패치를 그린 것을 볼 수 있다. 두줄의 경우에도 영역만 늘어났지 이미지가 늘어 나지 않은 것을 확인 할 수 있다. 패딩영역을 주어 텍스트가 모두 꽉 차지 않고 좌우 위아래 패딩이 적용되어 있는 것도 주의 깊게 살펴 보자.

 

1.7.7-1

나인패치 이미지

1.7.7-2

사용된 모습

<그림 1.7.7> 나인패치 입력필드 예제

예제2. 버튼

늘어나는 부분을 자세히 보면 하나가 아닌 여러개로 나눌 수 있다. 이렇게 나누게 되면 이미지가 늘어나게 되면 비율에 맞게 늘어 난다. 그림 1.7.8에서 보면 하단  검은색 줄이 좌우와 같은 비율로 늘어난 것을 볼 수 있다.

 

1.7.8-1

나인패치 이미지

1.7.8-2

사용된 모습

 

 

<그림 1.7.8> 나인패치 버튼 예제

 

 

나인패치의 숨기는 영역(Optical Bounds)

 

안드로이드 4.3(젤리빈) 부터 늘어나는영역, 패딩영역 이외 숨기고 싶은 영역을 지정할 수 있는 기능이 생겼다. 이 부분은 기존의 패딩영역의 위치인 왼쪽/하단 부분에 정의하여 검은색(#000000)이 아닌 빨강색(#FF0000)으로 정의한다.
1.7.9

<그림 1.7.9> 나인패치 숨기는 영역

이렇게 빨강색의 숨기는 영역을 정의하게 되면 이미지가 그려질때 보이지 않게 된다. 그림 1.7.10에서 보는 것과 같이 숨기는 영역을 적용 함으로 버튼의 상/하단과 위/아래 부분의 불필요한 영역이 없어졌다. 숨기는 영역은 정의한다고 바로 사용되는 것이 아니라 버튼을 감싸고 있는 레이아웃의 layoutMode의 opticalBounds값을 통해 사용가능하다.  안드로이드 4.3부터 사용가능하며 이전 버전에서는 동작하지 않는다.

 

1.7.10-1

숨기는 영역 비 적용

1.7.10-2

숨기는 영역 적용

<그림 1.7.10> 나인패치 숨기는 영역 적용

 

나인패치는 개발자 영역이지만 UI디자인시 나인패치를 감안해서 디자인을 하기 위해 디자이너도 반드시 알아둘 필요가 있다. 디자인 편집툴을 이용해서 나인패치영역을 선택하는 것보다 안드로이드에서 기존적으로 제공하는 툴을 이용하거나 Simple Nine-patch Generator 웹사이트(http://android-ui-utils.googlecode.com/hg/asset-studio/dist/nine-patches.html) 를 이용하면 쉽게 만들 수 있다.

 

 




외부이미지 나인패치 적용하기

해상도가 다양한 안드로이드는 배너영역의 이미지를 폰별로 최적화 하기는 힘들다. 그래서 고안된것이 디바이스별로 다양한 배너이미지를 만들어 폰 해상도에 따라 최적화된 이미지를 내려주는 방법(애드몹)도 쓰지만 정확하게 맞추기는 힘들고 관리하기도 힘들다.

이런 문제점을 안드로이드의 나인패치기능을 통해 조금이라도 해결가능하다. 예를들면 다음과 같은 결과를 얻을 수 있다.

원본 광고

나인패치(양옆으로만 늘리기)

나인패치(4개의 영역으로 균등하기 늘리기)

  • 공고이미지는 저랑 아무런 관계가 없으며 예시를 위해 사용된것뿐임.

직접 구현하기

안드로이드의 나인패치 이미지를 내부 리소스뿐만 아니라 외부이미지에 대해서도 적용이 가능하다. 외부이미지인 즉, 앱 내부에 리소스가 아닌 웹URL을 통해 가져온 이미지나 폰 내부에 있는 이미지도 나인패치를 체크해서 NinePatchDrawable로 만들 수 있다.

안드로이드 소소코드에서 Bitmap.java를 보면 decodeFile()메서드에서 나인패치영역을 저장하고 있으며, getNinePatchChunk()메서드를 통해서 나인패치가 적용된 이미지인지를 확인 할 수 있다.

그렇기 때문에 getNinePatchChunk()에 값이 있다면, Bitmap을 NinePathDrawable로 사용하여 나인패치가 적용가능하다. 

다음은 decodeFile()메서드 내부에 나인패치영역을 가져오는 loadNinePatchChunk()메서드이다. png파일을 체크 후 나인패치영역을 bytep[]로 변환해 주도록 구현되어 있다.

private static final byte[] loadNinePatchChunk(String name) {
    InputStream stream = name.getClass().getResourceAsStream(name);
    if (stream == null) {
        return null;
    }
    try {
        IntReader reader = new IntReader(stream, true);
        // check PNG signature
        if (reader.readInt() != 0x89504e47 || reader.readInt() != 0x0D0A1A0A) {
            return null;
        }
        while (true) {
            int size = reader.readInt();
            int type = reader.readInt();
            // check for nine patch chunk type (npTc)
            if (type != 0x6E705463) {
                reader.skip(size + 4/* crc */);
                continue;
            }
            return reader.readByteArray(size);
        }
    } catch (IOException e) {
        return null;
    }
}

NinePatchDrawable의 생성자를 보면 byte[] chunk가 있는데, Bitmap의 loadNinePatchChunk()메서드에서 가져온 chunk를 넘기면 나인패치이미지로 변환된다.

InputStream stream = .. //whatever
Bitmap bitmap = BitmapFactory.decodeStream(stream);
byte[] chunk = bitmap.getNinePatchChunk();
boolean result = NinePatch.isNinePatchChunk(chunk);
NinePatchDrawable patchy = new NinePatchDrawable(bitmap, chunk, new Rect(), null);

위와 같은 코드를 통해 Bitmap이미지에서 NinePatchDrawable로 변형하여 나인패치가 적용된 이미지를 사용 할 수 있게 된다.

*주의할점은 외부 이미지는 컴파일된 파일이어야 한다. 컴파일 방법은 http://forum.xda-developers.com/showthread.php?t=785012 를 참고하자.

Android Nine-patch Tips

안드로이드의 나인패치는 어플리케이션의 UI를 구성하는데 중요한 요소이다. 어떠한 크기로 확장 할 수 있도록 개발자 또는 디자이너로 하여금 사각영역을 지정 할 수있다. 개발하는 HDPI, XHDPI, XXHDPI 등 다양한 DPI를 지원해야 한다. 이런 점에서 나인패치는 아주 중요한 요소이다.

이런점에서 팁하나를 소개 하려한다.

Low DPI 나인패치 이미지를가지고 High DPI에 적용시(또는 반대의 경우) 문제점이 발생 하는데, 이를 대비 할 수 있는 방법이다. 보통 문제가 생겼는지도 잘 모른다. 혹시 나인패치 이미지의 색상이 기기의 DPI별로 다르게 나온 적이 있다면 이부분을 의심해야 할 듯 하다.

예를 들어 HDPI 나인패치 이미지를 만들어 drawable-hdpi 디렉토리에 넣었다고 치자. 보통 나인패치 영역을 최소화 하기 위해 아래처럼 반복되는 영역은 가장작게 1px로 잡는게 대부분이며, 반복되는 부분외 달라지는 부분의 영역의 여유분 없이 잡게 된다. 

이런 경우 문제가 생긴다.

왜?

안드로이드에서는 이미지를 리스케일링한다. 예를 들어 HDPI이미지를 만들어 넣었는데, XXHDPI의 단말기에서 실행 하면 DPI크기를 맞추기 위해 이미지를 리스케일링 하여 늘리게 된다. 

이렇게 리스케일링 과정중 스트레치 영역은 리스케일링되지 않기 때문에 충돌이 난다. 즉 스트레치 역영과 아닌 부분의 색상이 뒤섞여 버린다. 

팁!

이런 이미지 리스케일링시 충돌나지 않게 하려면 스트레치 영역에 여유분을 주면 된다.

1) 스트레치 영역은 적어도 2-4px로 잡는다.

2) 스크레치 영역외(반복해야 되는 부분중 스트레치 영역이 아닌부분)도 여유분의 공간을 준다.

이렇게 2가지점을 꼭 기억하면 나인패치 충돌을 막을 수 있다.

안드로이드 디자인 관련 작업 좀더 쉽게 하기

 


안드로이드는 디자인은 개발에 있어서 또는 디자인에 있어서 많이 복잡하고 까다로운건 사실이다. 다양한 DPI에 맞는 사이즈를 제작해야되며, 디자이너들에게는 생소한 나인패치라는것도 해봐야 한다.


 


안드로이드 디자인을 처음으로 하거나 아직 미숙한 디자이너들에게 도움될 만한 사이트를 소개하겠다. 안드로이드 SDK에 나인패치 툴이 있긴 하지만 설치하는 번거로움을 피할수 있고, 즉각적인 이미지를 확인 할 수 있다.


 


 



 


Simple Nine-patch Generator


 


이 외에도 얼마전 Navigation Drawer의 표준가이드가 생기면서 이에 맞는 인디케이터 아이콘도 생성할 수도 있다. (Navigation Drawer Indicator Generator)


노티케이션 아이콘도 API11 전후로 표준 가이드가 바꼈는데, 이에 맞게 아이콘을 변형해준다. (Notification Icon Generator)


이외 아래 다양한 디자인 관련 작업들이 가능하다. (참고로 크롬브라우저에서만 작동한다.)


 


Icon generators


Launcher icons


Action bar and tab icons


Notification icons


Navigation drawer indicator


Generic icons


Tab icons (pre-Android 3.0)


Menu icons (pre-Android 3.0)


 


Other generators


Device frame generator (or see the official version for Nexus devices)


Simple nine-patch generator


 


Community tools


Android Action Bar Style Generator by Jeff Gilfelt


Android Holo Colors Generator by Jérôme Van Der Linden


 


 


 

안드로이드 앱 개발자가 제안하는 디자인 방법론 – 2. 나인패치(Nine-patch) 실습

안드로이드 앱 개발자가 제안하는 디자인 방법론 – 2. 나인패치(Nine-patch) 실습

안드로이드 나인패치에 대한 두번째 시간으로 나인패치를 개발자가 어떻게 레이아웃을 잡아서 사용 하는지에 대해 알아보겠다.

나인패치에 대해 기억이 안난다면 이전 글을 다시 보고 이 글을 보도록 하자.

2013/02/28 – [개발관련/Android] – 안드로이드 앱 개발자가 제안하는 디자인 방법론 – 1. 나인패치(Nine-patch) 개념

 

저번 시간 마지막중에 4가지의 나인패치 이미지 예제를 주었다. 대표적으로 쓰이는 이미지로 어떤식으로 적용 되는지 하나하나씩 보자.

 

상단 타이틀이나 내용부분에 그라데이션을 주기 위해서 흔하게 쓰이는 이미지이다.

나인패치를 보면 상단좌측부분은 1px만큼 잡아 주었고, 하단우측부븐은 Full로 나인패치를 잡아 주었다. 

    

<Textview 
android:layout_width="100dip" 
android:layout_height="100dip" 
android:text="Contents" 
android:textcolor="@android:color/black">

위의 이미지는 나인패치를 가로 세로 100dip으로 강제로 늘린 것이다. Padding영역을 모두 잡아 주었기 때문에 앞으로 상단위쪽부분으로 Content 가 붙어 있는것을 볼 수 있다.

    

<Textview 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="Contents" 
android:textcolor="@android:color/black">

다음 이미지는 가로 세로 Content 크이게 맞게 늘어 나도록 적용되어 있다. 크기에 맞게끔 늘어 난것을 볼 수있다.  

    
<Textview 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:text="Contents" 
android:textcolor="@android:color/black">

가장 중요한 부분이다. 흔히들 나인패치를 잡을때 하는 실수..

이 부분도 역시 가로세로 Content 사이즈에 맞게 늘어 나도록 적용하였다. 하지만 Content 를 세로로 길게 넣었다.

자세히 보면 가로로 Content 크기에 맞지 않게끔 늘어 난(빨강색 부분) 것을 볼 수 있다. 왜이렇게 되었을까?

정답은 상단 나인패치 부분에 있다. 현재 점으로 하나만 잡고 양 옆으로 영역이 남아 있다. 이 부분이으로 인해 좀 더 늘어 난것이다. 정확하게 맞추기 위해서는 나인패치를 Full로 잡거나 1px로 최대한 작게 변경 하면 된다.

 

 

안드로이드 앱 개발자가 제안하는 디자인 방법론 – 1. 나인패치(Nine-patch) 개념

안드로이드 앱 개발자가 제안하는 디자인 방법론 – 1. 나인패치(Nine-patch) 개념

디자이너들이 웹에서 모바일(안드로이드 플렛폼) 환경으로 넘어 오면서 꼭 알아 두었으면 하는 내용을 정리하는 목적으로 연제글을 올리게 되었다. 

그 첫번째 시간으로 안드로이드에서 가장 중요한 나인패치(?)에 대해 설명 하겠다. 나인패치 하나만 잘 알아도 안드로이드 앱 개발자에게 무한 신뢰와 최고의 감각을 가진 디자이너로 인정받을 수 있으니 필히 정독 하자! 

나인패치에 대해 간단하게 설명 하자면, png 이미지로 되어 있는 Stretchable(늘어나는) 영역을 정의 할 수 있다. Stretchable영역 외에도 Padding영역을 선택 할 수 있다.

그렇다면 안드로이드에서는 왜 이런 나인패치라는 개념을 도입 했을까? 안드로이드는 제조사 마다 모두 다른 해상도의 device를 출시 한다. iOS iPhone의 경우 가로 해상도가 고정이기때문에 고정된 길이의 이미지를 사용해도 문제가 없을 것이다. 하지만 안드로이드의 경우 해상도는 다양하기 때문에 static한 이미지를 사용하게 된다면 늘어 날경우 아래와 같이 뭉게지게 된다. 

 

 

반면 나인패치를 적용 한경우 아무리 늘어나도 원본과 같은 이미지를 얻을 수 있다.

48x48px

160x96px

늘린이미지

그러면 “해상도에 따른 이미지를 각각 가지고 있으면 되지 않을까?” 라는 의문이 들수도 있다.

물론된다. 하지만 해상도에 맞는 적어도 10개가 되는 이미지를 만든다고 생각 해보라. 같은 이미지를 크기에 따라 10개를 만들어야 된다면 누가 디자인을 하려 하겠는가. 또한 앱 용량이 10배이상 늘어나게 되며 리소스를 관리도 무척이나 힘들다. 스마트폰의 어플리케이션의 특성상 한번의 개발로 끝이 아니라 지속 적인 유지 보수가 필요 한데 이러한 환경에서는 더더욱 힘들다.

이런 저런 생각으로 구글 안드로이드 플렛폼 개발자들은 “나인패치라”는 개념을 만들었다. 

하나의 이미지를 다양한 해상도를 가진 device에서 dynamic하게 보여 준다. 구글 개발자들은 매일 자전거타고 수영하고 놀고 있지않다는 증거이다.

그럼 어떻게 Stretchable영역이 늘어나는지 원리에 대해 자세히 설명 해보자.

윗 부분에 검은색선으로 가이드 라인을 잡았다. 그 검은색 선을 기준으로 이미지는 위와 같이 분해 된다.

검은색으로 선택했던 부분은 반복하는 패턴으로 인식 되어 늘어 나거나 줄어 들게되어 뭉게 지지 않는다. 늘어 나는게 아니라 패턴으로 반복되는 구조이다.

흑백으로 된 부분의 이미지는 늘어날 부분의 영역에 대해 아무런 영향을 미치지 않는다. 즉, 통이미지를 유지 한다.

그래서 나인패치된 이미지를 늘릴 경우 뭉게지는게 아니라 사용자가 선택했던 부분만 패턴으로 인식 되어 자연스럽게 늘어 나는것을 확인 할 수 있다.

초록색의 가이드라인사이에 

<span border-bottom:=”” 0px;=”” width:=”” 341px;=”” height:=”” 217px;=”” border-right:=”” 0px”=””>



늘린다음 왼쪽과 상단 부분에  잡는다. 



단순히 원본 이미지에 1px만큼의 테두리에 검은색(#000000)으로 늘어 나는 역영을 정의하면 된다. Nine-patch이미지는 .9.png 라는 확장자로 되어 있어야 안드로이드에서 Nine-patch이미지로 인식 하며, 이런 확장자를 붙여 주게 된다면 개발자들이 좋아 한다.



첫 부분에 Stretchable영역 외에도 Padding영역을 잡을 수 있다고 언급 했다. Padding영역잡는 것도 Stretchable영역 잡는 것과 비슷한 원리니 한번 알아 보자.

  • Stretchable영역: 왼쪽, 상단 
  • Padding영역: 오른쪽, 하단

Padding영역은 텍스트 또는 아이콘을 표시하는 등 컨텐츠에 사용되는 패딩을 지정 할 수 있다. 위 이미지 처럼(노랑색 테두리) 페딩역역이 잡히게 된다.

Nine-patch의 불편한 진실 

반복적인 패턴이 아닌 위 처럼 질감을 가진 이미지라면 Nine-patch를 피하라. 필요한 정적이미지 즉, 통이미지를 써야 한다.

이런 부분만 뺀다면 Nine-patch는 그럭저럭 쓸만 할것이다.

이상 나인패치에 대해 알아 보았다. 다음 시간에는 좀 더 다양한 예제들을 가지고 실제 상황에서 어떤식으로 나타는지, 영역을 잡는지에 대해 알아 보겠다.

그리고 Nine-patch Tool에 대해서도 간단히 언급 하겠다.

 

 

아래 실제 사용중인 Nine-patch 예제를 몇개 모아 두었으니, 늘어나는 영역과 패딩영역이 늘어날때 어떻게 될지 미리 한번 생각 해보길 바란다.