태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

홈스크린 위젯을 만들어보자! - 간단한 위젯 작성하기

2010.10.24 21:57

여러 종류의 홈스크린 위젯의 모습


안드로이드는 애플리케이션의 목록이 표시되는 애플리케이션 런처(Application Launcher)와 별도로, 사용자가 임의로 꾸밀 수 있는 화면인 홈 스크린(Home Screen)을 제공합니다. 

홈 스크린은 단말기를 사용할 때 가장 처음 접하게 되는 화면이며, 사용자의 취향에 따라 다양한 요소를 배치하여 자신에 맞는 홈 스크린을 만들 수 있습니다. 홈 스크린에 배치할 수 있는 요소는 다음과 같습니다.

  • 애플리케이션 아이콘
  • 폴더/라이브 폴더
  • (특정 작업의)바로가기
  • 홈스크린 위젯

이번 강좌에서는 위 4가지 요소 중 사용자에게 가장 풍부한 기능을 제공할 수 있는 홈 스크린 위젯(이하 '위젯')을 작성하는 방법에 대해 알아보겠습니다.


위젯의 기초

위젯은 홈스크린의 일정 공간을 차지합니다. 홈스크린에서 위젯이 차지할 수 있는 공간은 홈스크린을 일정한 비율로 나눈 영역인 셀(Cell) 단위로 관리되며, 위젯의 크기는 셀을 몇 개 사용하느냐에 따라 결정됩니다.

일반적으로 안드로이드 단말에서 위젯이 차지할 수 있는 홈스크린 영역은 다음과 같이 가로 4개, 세로 4개 총 16개로 나누어집니다.

홈스크린에서 위젯이 차지할 수 있는 영역 구성


각 위젯은 최소 1개의 셀부터 시작하여 최대 16개의 셀을 차지할 수 있으며, 사각형 형태로만 셀을 차지할 수 있습니다. (4x1, 2x2 등) 위젯이 차지하는 셀의 크기는 매니페스트의 위젯 노드에서 설정하며, 이에 대한 자세한 사항은 잠시 뒤에 살펴보겠습니다.

하나의 위젯을 만들려면 몇 가지 절차를 거쳐야 하는데, 그 절차는 다음과 같습니다.

  • 위젯 레이아웃 작성하기
  • 위젯 프로바이더 작성하기
  • 매니페스트에 위젯 등록하기
  • 위젯 클래스 작성하기

위젯 레이아웃 작성하기

위젯을 만들려면, 먼저 위젯의 레이아웃을 작성해야 합니다. 위젯은 홈스크린에 바로 표시되기 때문에, 위젯의 배경을 지정해야 해당 위젯을 홈스크린에서 쉽게 식별할 수 있습니다. 이 때문에, 일반적으로 위젯 레이아웃을 구성하는 최상위 뷰의 배경에 위젯 배경 이미지를 지정합니다.

위젯 배경 이미지는 자신이 만들 위젯의 크기에 맞게 작성하면 됩니다. 크기별 위젯 바탕 이미지 예제는 개발자 사이트의 위젯 가이드라인 페이지 (http://developer.android.com/guide/practices/ui_guidelines/widget_design.html)에서 구할 수 있으며, 이 페이지에 위젯을 디자인할 때 고려해야 할 내용들도 기술되어 있으므로 위젯 디자인시 참고하는 것이 좋습니다.

[어플리케이션 정보]

액티비티
  • 없음

레이아웃
  • simple_widget_layout.xml (위젯 레이아웃)

XML
  • simplewidget.xml (위젯 프로바이더)


API Level

  • 8 (Android 2.2)


위젯 가이드라인 페이지의 4x1 크기 위젯 배경 이미지 예제를 사용하여 예제 위젯을 만들어보도록 하겠습니다. 위젯의 레이아웃을 작성한 후, PSD 형식으로 되어 있는 예제 이미지를 다운로드하여 PNG 형식으로 변환한 하고 다음과 같이 위젯의 배경으로 지정합니다. 여기에서는 위젯 배경 이미지의 이름을 widget_background_4_1.png로 지정하였습니다.

[simple_widget_layout.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:background="@drawable/widget_background_4_1"
	android:gravity="center"
	android:layout_height="wrap_content"
	android:layout_width="fill_parent"
>
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="Hello, Widget!"
		android:textColor="#000000"
		android:textSize="20dp"
		android:id="@+id/simple_widget_layout_text"
	/>
</LinearLayout>
[코드 1]


홈스크린 위젯의 특성상 위젯 레이아웃에 사용할 수 있는 레이아웃 및 뷰에 한계가 있습니다. 홈스크린 위젯에서 사용할 수 있는 레이아웃 및 뷰는 다음과 같습니다.

레이아웃 :
FrameLayout
RelativeLayout
LinearLayout

뷰 :
AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView



코드1에서 작성한 위젯 레이아웃은 다음과 같이 화면에 표시됩니다.

예제로 작성할 위젯의 모습



일반적으로 액티비티 레이아웃을 작성할 때와 달리, 위젯 레이아웃을 지정할 때는 위젯을 구성하는 컴포넌트의 배치만 관리할 뿐, 위젯의 전체 크기에는 관여하지 않습니다. 즉, 코드1에서 위젯을 감싸고 있는 LinearLayout의 layout_width, layout_height 속성을 변경해도 위젯의 크기에는 영향을 미치지 않습니다.


위젯 프로바이더 작성하기

위젯 레이아웃 작성이 끝났다면, 위젯 속성을 담고 있는 위젯 프로바이더를 작성합니다. XML 추가 마법사를 연 후, XML 종류에 AppWidget Provider를 선택하여 위젯 프로바이더를 생성합니다.

위젯 프로바이더를 생성합니다.



위젯 프로바이더를 생성하면 다음과 같이 위젯의 속성을 지정할 수 있습니다.


위젯 프로바이더에서는 총 5개의 속성을 지정할 수 있습니다. 각 속성의 의미는 다음과 같습니다.


Min width, Min height

화면에 표시되는 위젯의 크기는 위젯 프로바이더의 Min width, Min height 속성에 따라 결정됩니다. 위젯은 셀(Cell) 단위로 홈스크린의 공간을 차지합니다. 홈 스크린의 화면 전환을 감안하면 한 셀의 한 변이 가질 수 있는 최소 크기는 74dp 입니다. 여기에서 안드로이드 단말의 다양한 해상도로 인해 위젯이 화면에 표시될 때 오차가 발생하는 것을 감안하여 양 쪽에 1dp씩을 빼주면, 실질적으로 한 셀의 한 변이 가질 수 있는 최소 크기는 72dp가 됩니다. 

셀 크기에 따른 최소 크기를 계산하는 공식은 다음과 같습니다.

(셀 개수 * 74) - 2 (단위 : dp)

위의 공식을 사용하여 계산한 셀 개수에 따른 최소 크기는 다음과 같습니다.


위에서 계산한 수치를 통해 일반적으로 많이 쓰이는 위젯의 크기를 정리해보면 다음과 같습니다.


여기에서는 4x1 크기의 위젯을 작성하므로, Min width에 294dp, Min height에 72dp를 지정하였습니다. 


Update period millis

위젯을 업데이트할 주기이며, 밀리초 단위로 지정합니다. 단, 여기에 지정한 주기대로 정확히 업데이트 되는 것은 보장할 수 없으며, 이 주기에 따라 업데이트를 실시할 경우 매 업데이트시마다 휴대폰이 활성 상태로 전환됩니다.

하루에 3~4번 정도 주기로 업데이트 되는 것은 큰 영향을 미치지 않겠지만, 만약 이 주기가 짧을 경우 활성 상태 전환으로 인해 배터리 소모가 증가할 수 있습니다. 이를 해결하려면 위젯을 자동으로 업데이트 하도록 하지 않고 AlarmManager 등을 사용하여 수동으로 업데이트 하도록 하면 됩니다. 수동으로 위젯을 업데이트하려면 Update period millis를 0으로 설정하면 됩니다.


Initial layout

위젯의 초기 레이아웃을 지정합니다. 인터넷에서 정보를 수신하여 표시해주는 위젯의 경우 초기 레이아웃에 정보 수신을 알려주는 문구를 지정하여 사용자에게 현재 상태를 알려줄 수 있습니다. 현재 예제에서는 위젯을 바로 업데이트할 수 있으므로, 위에서 만든 레이아웃을 Initial layout으로 지정하여 바로 위젯이 표시되도록 합니다.


Configure

위젯의 크기, 표시 내용 등을 설정할 수 있는 액티비티를 지정합니다. 패키지 이름을 포함한 액티비티의 클래스 이름을 적어주며, 설정 액티비티는 위젯이 홈스크린에 추가되지 전에 표시됩니다. 별도로 설정할 항목이 없다면 이를 비워두면 됩니다.


매니페스트에 위젯 등록하기

이제 매니페스트에 위젯을 등록할 차례입니다. 홈스크린 위젯은 AppWidgetProvider를 상속받으며, AppWidgetProvider는 브로드캐스트 리시버를 상속받으므로 매니페스트에 등록할 때는 Receiver 노드를 사용합니다. 

매니페스트에 Receiver 노드를 추가한 후, 위젯 클래스를 추가하기 전에 위젯에 필요한 속성들을 지정합니다. 매니페스트에서 위젯이 가져야 할 속성은 다음과 같습니다.

  • android.appwidget.action.APPWIDGET_UPDATE 액션을 가지는 브로드캐스트 메시지 수신
  • 위젯 속성을 가지고 있는 Meta data

android.appwidget.action.APPWIDGET_UPDATE 브로드캐스트 메시지 수신하기

인텐트 필터를 추가하고 액션을 추가한 후, Name에 android.appwidget.action.APPWIDGET_UPDATE를 입력합니다.


Meta data 추가하기

위젯의 속성을 가지고 있는 위젯 프로바이더를 연결해주기 위해, Meta data를 추가한 후 다음과 같이 Name에 android.appwidget.provider를, Resource에는 위젯 프로바이더를 지정합니다.



위젯 클래스 작성하기

이제 매니페스트에 지정할 속성은 모두 지정했습니다. 다음과 같이 Receiver 노드를 선택한 상태에서 오른쪽 속성창의 Name*을 눌러 위젯 클래스를 추가합니다.


다음과 같이 새 클래스를 추가하는 대화상자가 표시됩니다. 위젯 클래스 이름을 지정하고, Superclass에 android.appwidget,AppWidgetProvider를 입력합니다.


위젯 클래스 파일이 생성되면, 위젯을 업데이트시 위젯을 표시하기 위해 다음과 같이 onUpdate() 메서드를 추가합니다.

[MySimpleWidget.java]
public class MySimpleWidget extends AppWidgetProvider {

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
		
	}
}
[코드2]

AppWidgetProvider에서는 상태에 따라 총 4개의 콜백 메서드가 호출되며, 각 메서드에서 수행해야 할 작업은 다음과 같습니다.


AppWidgetProvider는 브로드캐스트 리시버를 상속받은 클래스이므로 onReceive() 메서드가 구현되어 있습니다. 위의 콜백 메서드는 AppWidgetProvider의 onReceive() 메서드에서 수신한 브로드캐스트 메시지의 액션에 따라 호출되도록 구현되어 있습니다. AppWidgetProvider의 onReceive() 구현부는 다음과 같습니다.

    public void onReceive(Context context, Intent intent) {
        // Protect against rogue update broadcasts (not really a security issue,
        // just filter bad broacasts out so subclasses are less likely to crash).
        String action = intent.getAction();
        if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null) {
                int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
                if (appWidgetIds != null && appWidgetIds.length > 0) {
                    this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
                }
            }
        }
        else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
                final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
                this.onDeleted(context, new int[] { appWidgetId });
            }
        }
        else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
            this.onEnabled(context);
        }
        else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
            this.onDisabled(context);
        }
    }

[코드3]

여기에서는 간단하게 위젯을 화면에 표시하는 것만 구현할 것이므로, 위의 콜백 메서드 중 onUpdate() 메서드만 구현하겠습니다. onUpdate() 메서드를 다음과 같이 구현합니다. 

[MySimpleWidget.java]
	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
        final int N = appWidgetIds.length;

        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.simple_widget_layout);
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
	}
[코드4]

onUpdate() 메서드는 세번째 인자로 appWidgetIds 배열을 받습니다. 이 배열에는 이 위젯 인스턴스들의 ID가 포함되어 있으며, 위젯을 업데이트시 우리가 만든 위젯을 사용하는 모든 위젯을 업데이트하기 위해 코드4와 같이 for문을 사용하여 현재 등록된 위젯들을 모두 업데이트합니다.

for문 내부를 보면 RemoteViews를 사용하는 것을 볼 수 있습니다. RemoteViews는 위젯의 레이아웃 및 컴포넌트의 동작 처리에 사용하는 클래스로, 생성자에서 우리가 만든 위젯 레이아웃을 지정하는 것을 확인할 수 있습니다. 여기에서는 별도로 컴포넌트의 동작을 지정하지 않으므로 바로 updateAppWidget() 메서드를 사용하여 위젯을 화면에 표시합니다.

이것으로 예제가 완성되었습니다. 실행을 누르면 위젯이 단말기에 설치됩니다. 위젯을 설치하였다면, 홈스크린에 우리가 만든 위젯을 추가해보도록 하겠습니다. 홈스크린을 길게 눌러 위젯을 선택하면, 목록에 우리가 만든 위젯이 표시되는 것을 확인할 수 있습니다.

위젯 목록에 우리가 만든 위젯인 SimpleWidget이 표시됩니다.


SimpleWidget을 선택하면 다음과 같이 위젯이 홈스크린에 등록됩니다.

SimpleWidget이 홈스크린에 등록된 모습


이것으로 간단한 위젯을 만드는 것에 대해 알아보았습니다. 액티비티 위주의 애플리케이션과는 다른 점들이 많아 처음에는 혼동이 많겠지만, 몇 번 연습해보면 쉽게 익숙해질 것입니다.

다음 강좌에서는 위젯에 버튼을 추가하고, 위젯을 업데이트하는 것에 대해 알아보겠습니다.
저작자 표시 비영리 변경 금지
신고

커니 유저 인터페이스/홈스크린 위젯 , , , , , , , , ,

  1. Blog Icon
    Dark

    안녕하세요 커니님글 잘 읽고 있습니다. 이번에 위젯을 해볼려고 따라해보는데 잘 되지가 않는군요. 올리신 소스코드와 내용은 똑같은데 AVD에서 위젯리스트에 나오지가 않습니다. 타겟만 다르게 했는데 안되는군요. 커니님의코드는 2.2 인데 전 2.1에서 해보았는데 되지가 않는군요. 혹시 이 문제에 대해서 알고 계신지 여쭤봅니다 ㅠ.ㅠ

  2. Blog Icon
    쌩초보..

    안녕하세요 커니님.
    생초보인 저에게는 글들이 많은 도움이 됩니다.
    하나 궁금한게 있어서 질문드립니다.
    현재 위 강의는 위젯을 추가하고 부팅하고 위젯을 선택하지않습니까?
    그런데 저는 안드로이드에 올라가있는 디폴트홈스크린 자체를 변경하고 싶습니다. 안드로이드 os 를 사용은하는데 기기가 전화기능같은건 필요가없어 불필요한건 삭제하고 필요한건 추가하고 싶습니다. 구글링을 해보니 ./packages/apps/Launcher2 쪽에서 해야된다는거 같은데 이곳저곳 건들여보는데 뭔가 바뀌는것이 없어서 더 답답합니다..
    디폴트 홈스크린 자체를 변경하는 방법을 아시나요 ? 그리고 위 강의에서 위젯 영역밑에 전화기능 아이콘 어플리케이션 리스트아이콘 인터넷 아이콘이 표시된 부분도 디폴트 홈스크린을 수정하면 수정할수 있는 섹션인가요 ..?

  3. 홈스크린 자체를 변경하려면 다른 홈 애플리케이션을 받아 설치하시면 됩니다. ADW Launcher나 LauncherPro 같은 앱들이 있겠죠.

    자신이 홈 애플리케이션을 만들고 싶다면 말씀하신대로 AOSP의 홈 소스를 받아온 후 수정하셔야 합니다. :(

  4. Blog Icon
    BobRoss

    강의 잘 봤습니다. 커니님,
    질문이 하나 있습니다.

    위젯을 추가시, 홈 스크린에 바로 뜨는것이 아니라
    설정 액티비티로 넘어간 뒤, 그 설정대로 위젯에 뿌려주려고 합니다.
    즉 , 위젯추가 선택 -> 설정 액티비티 (텍스트나 칼라등을 선택함) OK 버튼 -> 위젯장착
    이렇게 하려고 합니다. 어떠한 개념으로 해야할지 ㅠ_ㅠ 조언좀 부탁드립니다..

  5. Blog Icon

    비밀댓글입니다

  6. 설정 액티비티를 사용하려면 위젯 리소스의 Configure에 설정 액티비티를 지정해야 합니다. 자세한 사항은 http://developer.android.com/guide/topics/appwidgets/index.html 의 Updating the App Widget from the configuration activity 부분을 참조하세요.

  7. Blog Icon
    Thong

    강좌 항상 잘 보고 있습니다.
    현재 player appWidget을 제작하려고 하는데 ,
    Player까지는 이미 제작을 해뒀는데 appWidget하고 연동을 우찌 시켜야 할지 감이 안옵니다 ㅜㅜ
    음악 제목도 가져오고.. next 버튼 등도 사용하고 싶은데 어떻게 하면 좋을까요? ㅜㅜ

  8. 플레이어가 서비스를 이용하고 있을 것 같은데,
    앱위젯에서 서비스에 접속하여 현재 재생중인 곡의 정보를 받을 수 있게 한다면 간단히 처리할 수 있을 것 같네요 :)

  9. 위 예제(첨부파일)에서 버튼을 누르면 엑티비티로 가는데 그걸 (Uri.parse(www.google.com)) 으로 바꾸니까 버튼 눌러도 반응이 없네요
    인터넷 퍼미션 해야되나요? 아니면..

  10. Blog Icon
    지나가는이
  11. 넵. 인터넷 퍼미션 지정해주셔야 합니다.

  12. 잘보고 갑니다

  13. Blog Icon
    반갑습니다

    커니님 반갑습니다 위젯관련 글을 보던중 글을 남기네요
    혹시 1번 런처랑 2번 런처가 있을때
    1번이 위젯 쏠림현상이 있습니다 폰이 qhd용인데요
    2번런처를 사용할경우 위젯쏠림은 없습니다
    1번위젯의 문제인것 같은데요 이런경우 어디 부분을 만져줘야 빈공간없이 4x2다 채울수 있게 만들수 있을까요..
    죄송하지만 질문을 드립니다

  14. Blog Icon
    answer

    잘보고 갑니다
    정리가 아주 잘 되어있네요^^

  15. Blog Icon