본문 바로가기

안드로이드

안드로이드 Menu

1. 안드로이드 Menu 종류

 

안드로이드 메뉴는 현재 화면에 보이는 Activity가 제공하는 Option Menu

Activity내의 개별 view들이 제공할 수 있는 Context Menu 두 가지가 있다.

 

 

A. Option Menu

현재 작동중인 Activity를 위한 menu이며 디바이스의 menu키를 누르면 나타난다.

Option menu는 처음 option menu를 호출 시 activity:onCreateOptionMenu(Menu) callback에서 초기화된다. onCreateOptionMenu(Menu)는 해당 activity가 생성돼서 처음 option menu가 호출 됐을 때 한번만 실행된다.

public boolean onCreateOptionsMenu (Menu menu)

parameter

menu: 시스템에 의해 생성된 menu 객체. 이 객체에 Menu:add(…) 메소드, MenuInflater 등을 사용하여 menu item을 추가함

return

true: 메뉴가 화면에 표시됨

false: 메뉴가 화면에 표시되지 않음

 

onCreateOptionMenu(Menu)를 통해 한번 초기화된 option menu의 아이템을 추가/삭제 하거나, 설정을 변경 (보이지 않게 설정하는 것 등) 하려면 option menu가 화면에 표시되기 바로 전에 항상 호출 되는 Activity:onPrepareOptionMenu(Menu) callback을 사용 한다.

public boolean onPrepareOptionsMenu (Menu menu)

parameter

menu: 본 메소드를 호출한 Activity의 option menu이다. 이 메소드가 완료되면 화면에 보여질 메뉴 객체임으로 화면에 보여지기 전에 변경 작업이 필요하면 이 메소드 내부에서 수정

return

true: 메뉴가 화면에 표시됨

false: 메뉴가 화면에 표시되지 않음

 

 

Option Menu는 다음 두 가지 menu로 구분 된다.

Icon Menu

디바이스의 menu 버튼을 눌렀을 때 안드로이드 스크린 밑 쪽에서부터 올라오며, 최대 여섯 개까지의 text + icon(옵션) 형태의 메뉴를 표시한다. option menu의 총 항목 개수가 6개를 초과하면 마지막 6번째 icon menu 버튼은 more로 표시된다.

 

Expanded Menu

option menu의 총 항목 개수가 6개를 초과해서 마지막 6번째 icon menu 버튼이 more로 표시되었을 때 이를 사용하면 나오는 text기반 list형식의 메뉴이다.

 

 

 

B. Context Menu

Activity 내부의 view가 제공할 수 있는 text기반의 list 메뉴이며, context menu를 제공하는 view를 약 2초 정도 터치&홀드 하면 화면 중앙에 출력된다. Activity에 포함된 모든 view가 개별적인 context menu를 가질 수 있음으로 여러 개의 context menu를 구현 해야 하는 경우도 있다. 예를 들어 TextView기반 view의 context menu는 text의 size에 대한 menu를 제공 하고, ImageView기반 view의 context menu는 image에 tint를 입히도록 menu를 구성 할 수 있다. (포스트 마지막의 예제 참조)

 

먼저 특정 view가 Context Menu를 제공하게 하려면 Context Menu 제공 view임을 Activity에 알려야 하는데, Activity:onCreate(Bundle) callback 내부에서 Activity:registerForContextMenu(View) 메소드를 사용한다.

public void registerForContextMenu (View view)

parameter

view: Context Menu를 제공할 view를 지정

 

그 다음 context mmenu의 초기화는 Activity:onCreateContextMenu(...) callback 내부에서 한다. Context Menu는 Option Menu와는 다르게 화면에 표시될 때 마다 항상 onCreateContextMenu(…)가 실행된다. (Option menu는 초기에만 한번 onCreateOptionMenu가 실행되고 그 이후에 option menu가 필요할 때는 onPrepareOptionMenu가 호출됨)

public void onCreateContextMenu (ContextMenu menu,
                                              View v,
                                              ContextMenu.ContextMenuInfo menuInfo)

parameters

menu: 시스템에 의해 생성된 Context Menu 객체이며, 이 객체에 add(…) 메소드나 MenuInflator를 이용하여 menu아이템을 추가 하는 등의 작업을 함

v: Context Menu를 소유한 view 인스턴스

menuInfo: context menu가 표현할 menu item에 대한 추가 정보를 전달 하는 역할을 하며, 어떤 종류의 view가 context menu를 호출 했는지에 따라 내용이 다름

 

다음 그림은 2개의 다른 view에 각각의 Context Menu가 구현된 예이다.

 

 

 


 

 

 

2. Menu 초기화 하기 (Populating Menu)

 

안드로이드에서는 system이 제공(callback 메소드의 인자로)하는 빈 Menu 객체에 SubmenuMenu item을 자유롭게 추가해 원하는 형태의 메뉴를 생성한다.

 

Menu item은 메뉴에서 사용자가 조작할 수 있는 menu요소를 말하며,

 

Submenu는 어떠한 기준(기능, 목적 등)을 바탕으로 그룹화된 메뉴 아이템들을 수용하는 컨테이너 역할을 한다. 예를 들어 PC어플리케이션의 경우 보통 File, Edit등의 메뉴가 자신의 이름과 관련 있는 child 메뉴들(new, save, save as 등등)를 포함하는데, 이 File, Edit가 안드로이드의 Submenu에 해당한다. 서브메뉴는 Option menu 또는 Context menu에서 모두 사용 가능하나, submenu 가 또 다른 submenu를 포함하는 구조는 허락되지 않는다.

 

 

다음은 TextView가 보여주는 Context Menu의 아이템을 submenu로 구성한 예이다.

그림에서는 3개의 텍스트 크키에 관한 menu item 3개가 그룹을 이뤄 'Text Size 설정 >' submenu를 형성하고 있다.

 

 

 

안드로이드는 Menu 초기화를 위해

Menu:add(…) 메소드를 이용하는 방법

XML & MenuInflater를 이용하는 방법을 제공한다.

 

A. Menu:add(…) method를 이용한 메뉴 초기화

이 방법은 onCreateOptionMenu(Menu) 나 onCreateContextMenu(Menu)에서 인자로 제공된 Menu객체와 Menu:add(…)/addSubmenu(…) 메소드를 이용해 소스코드 내부에서 직접 메뉴를 디자인하는 방법이다. 프로그램 로직과 디자인이 합쳐져 코드가 복잡해지는 단점이 있어 권장되지 않는다.

Menu 객체는 여러 형태로 오버로딩 된 add(…) 메소드를 제공하는데, 그 중 가장 많이 사용되는 메소드는 다음과 같다.

abstract MenuItem add(int groupId, int itemId, int order, CharSequence title)

parameters

groupId: 메뉴 아이템 그룹을 int 형으로 지정하며, 같은 그룹으로 묶인 item들은 Menu클래스의 그룹 속정 지정 메소드(ex. Menu:setGroupCheckagle(), setGroupEnabled(), setGroupVisible() 등)를 적용 가능하다. 그룹 지정을 하지 않으려면 pre-define된 상수 Menu:NONE이나 숫자 0을 전달하는 것이 일반적이다.

itemId: 코드 상에서 메뉴 아이템간의 구분을 위한 구분자(identifier). 당연히 아이템 마다 유일한 0-based integer를 부여해야 한다.

order: 메뉴 아이템이 표시될 순서를 지정. 0이 가장 처음 표시되며 숫자가 클수록 나중에 표시됨. 모두 같은 숫자로 지정되면 메뉴에 추가된 아이템 순으로 보여짐.

title: 메뉴 아이템이 표현할 text값을 지정.

return

생성한 MenuItem 객체를 리턴

 

 

또, Menu클래스는 SubMenu 추가를 위해 다음과 같은 메소드도 제공한다.

(일반적으로 submenu는 이벤트 처리가 필요 없기 때문에 addSubMenu(CharSequence title)도 많이 사용된다)

abstract SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title)

parameters

위에 설명한 MenuItem add(…) 메소드의 parameter와 동일

return

생성한 SubMenu 객체를 리턴

 

 

그럼 위의 메소드가 onCreate…Menu(Menu) callback내부에서 어떻게 사용되는지 살펴보자.

접기

01 @Override
02 public boolean onCreateOptionsMenu(Menu menu) {
03     boolean result = super.onCreateOptionsMenu(menu);
04      
05     // Group ID없으며, 각각 이름이 Red, Green, Blue인 아이템을 menu객체에 추가
06     // 아이템은 순서대로 1, 2, 3의 아이템 ID를 부여 받았다.
07     // 또 순서가 2, 1, 0 순으로 되어있어 Blue가 가장처음 Red가 가장 나중에 표시된다.
08     menu.add(Menu.NONE, 1, 2, "Red");
09     menu.add(Menu.NONE, 2, 1, "Green");
10     menu.add(Menu.NONE, 3, 0, "Blue");
11      
12      
13     // Menu에 Submenu(Size)을 추가
14     SubMenu subMenu = menu.addSubMenu("Size");
15      
16     // 위의 서브 메뉴에 Group ID가 1이며, 각각 이름이 10, 20, 30cm인 아이템 추가
17     // 각각의 아이디는 순서대로 4, 5, 6 ID를 부여 받았다.
18     // 순서는 모두 0임으로 추가된 순서대로 화면에 보여짐.
19     subMenu.add(1, 4, 0, "10cm");
20     subMenu.add(1, 5, 0, "20cm");
21     subMenu.add(1, 6, 0, "30cm");
22      
23     return result;
24 }

접기

 

 

위와 같이 생성된 option menu는 실행 시 다음과 같은 형태로 표현된다.

Blue, Green, Red는 item이고 Size는 Submenu임으로 추가의 아이템을 화면에 표시한다.

 

 

 

B. XML과 MenuInflator를 이용한 메뉴 초기화

이 방법은 XML 기반의 문서(\res\menu\ 폴더에 저장 됨)에 메뉴의 형태를 기술 하고, 소스 코드 내부에서 XML 파일을 inflate하여 메뉴의 초기 모양을 구성하는 방법이다. 어플리케이션 로직과 디자인을 분류함으로 간결한 코드를 만들 수 있음으로 권장되는 방식이다. 또, menu XML 문서는 메뉴 생성 visual tool (eclipse ADT plug-in도 제공하는)들을 사용해 쉽게 만들거나 수정 할 수 있다는 장점도 있다.

 

menu XML문서는 다음 세 가지 element를 이용하여 작성 한다.

<menu>

menu xml 문서의 root element이다. <item>과 <group> element를 포함(nest)할 수 있으며, submenu구성을 위해 <item> element 밑에 포함되기도 한다. 관련 attribute는 없다.

 

<group>

item들을 그룹으로 묶기 위해 사용되는 element이며, <item> element를 포함한다. 지원 attribute는 다음과 같다.

  • android:id – 그룹별로 유일한 구분자(identifier)를 설정하는데 사용.
  • android:menuCategory – 그룹의 우선순위를 지정한다. 사용 할 수 있는 값은 alternative, secondary, container, system (이상 높은 우선순위 순서 정렬)이며, 각각의 값은 Menu클래스에 pre-define된 상수 CATEGORY_ALTERNATIVE, CATEGORY_SECONDARY, CATEGORY_CONTAINER, CATEGORY_SYSTEM에 대응한다. 또, 같은 category에 속하고 item 별 우선 순위가 부여되지 않은 item들은 선언된 순서대로 표현된다. (왜 이런 이름을 사용해 우선 순위를 정했는지 알 수 없음. 단지 코드에서 test해본 결과 이런 순서로 메뉴가 표시됨, 또 이 attribute를 지정하지 않은 group이 최 우선 순위로 배치됨. 결국 category없음 > alertnative > secondary > container > system로 우선순위가 결정됨)
  • android:orderInCategory – 같은 category 안에서의 우선순위를 0-based integer로 설정.
  • android:checkableBehavior – group 내부의 item들이 check가능한지 설정. 유효 값은 none, all(checkbox처럼 각 아이템이 동시에 check될 수 있는 그룹), single(radio button처럼 한번에 하나만 check되는 그룹)
  • android:visible – 그룹의 시각적 활성화 여부를 결정. 유효 값은 true, false
  • android:enabled – 그룹의 활성화 여부를 결정. 유효 값은 true, false

 

<item>

item은 메뉴에서 사용자가 선택 가능한 element를 나타낸다. group, menu(submenu를 구성하기 위해) element를 포함 할 수 있다. 다음은 지원하는 attribute들 이다.

  • android:id – item별 유일한 구분자(identifier)를 설정.
  • android:menuCategory - <group> element의 menuCategory와 동일.
  • orderInCategory - 같은 category 안에서의 item간 우선순위를 0-based integer로 설정.
  • android:title – item이 화면에 보여지는 이름을 설정.
  • android:titleCondensed – 일반 타이틀이 너무 길어 화면에 온전히 표시 할 수 없을 경우 대신 사용되는 간결한 title. Option Menu는 titie대신 이 속성을 사용한다.
  • android:icon – item의 icon을 설정. (예. "@drawable/icon" )
  • android:alphabeticShortcut – item의 쇼트키를 영문자 중 지정. 유효 값은 영문 알파벳 대소문자 구분 없이 한 글자, \n(enter키), \b(delete키).
  • android:numericShortcut – item의 쇼트키를 숫자 중 지정. 유효 값은 0~9.
  • android:checkable – item이 check가능한지 설정. 유효 값은 true, false.
  • android:checked – 메뉴가 처음 표시될 때 item을 check상태로 표시 할 지 여부 지정. 유효 값은 true, false.
  • android:visible – 메뉴 item의 시각적 활성화 여부 지정. 유효 값은 true, false.
  • android:enable – 메뉴 item의 활성화 여부 지정, 유효 값은 true, false

 

 

설명한 3가지 element를 이용하여 A. Menu:add(…) method를 이용한 메뉴 초기화에서 구현했던 것과 같은 메뉴를 구성해보자.

my_menu.xml

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <item
04         android:id="@+id/menuRed"
05         android:title="Red"
06         android:orderInCategory="2" />
07     <item
08         android:id="@+id/menuGreen"
09         android:title="Green"
10         android:orderInCategory="1" />
11     <item
12         android:id="@+id/menuBlue"
13         android:title="Blue"
14         android:orderInCategory="0" />
15     <item
16         android:id="@+id/subSize"
17         android:title="Size"
18         android:orderInCategory="4" >
19         <menu>
20             <group
21                 android:id="@+id/groupSize" >
22                 <item
23                     android:id="@+id/size10"
24                     android:title="10cm" />
25                 <item
26                     android:id="@+id/size20"
27                     android:title="20cm" />
28                 <item
29                     android:id="@+id/size30"
30                     android:title="30cm" />
31             </group>
32         </menu>
33     </item>
34 </menu>

접기

 

완성된 my_menu.xml을 \res\menu 폴더에 저장하고 java코드의 onCreateOptionMenu(Menu)에서 다음과 같이 inflate 한다. 코드상에서 직접 메뉴를 디자인 했을 때보다 코드가 훨씬 간결해 졌음을 확인 할 수 있다.

XML inflating code

접기

1 @Override
2 public boolean onCreateOptionsMenu(Menu menu) {
3     boolean result = super.onCreateOptionsMenu(menu);
4      
5     MenuInflater menuInflator = new MenuInflater(this);
6     menuInflator.inflate(R.menu.my_menu, menu);
7      
8     return result;
9 }

접기

 

 

실행 시켜보면, add() 메소드를 사용해 코드 내부에서 menu를 디자인 했을 때와 완전히 동일한 메뉴가 생성된다.

 

 

 

 




3. Menu item 꾸미기

 

A. Icon 추가


icon은 Option Menu의 icon menu 에서만 사용 가능하다. (Option menu의 Expanded menu에서도 icon표시 안됨)

자바 코드에서의 설정 예

접기

01 @Override
02 public boolean onCreateOptionsMenu(Menu menu) {
03     boolean result = super.onCreateOptionsMenu(menu);
04      
05     MenuItem item = menu.add(0, 1, 0, "Text+Icon 1");
06     item.setIcon(R.drawable.icon);
07      
08     menu.add(0, 2, 0, "Text+Icon 2")
09         .setIcon(R.drawable.icon);
10      
11     return result;
12 }

접기

 

 

XML에서의 설정 예

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <item
04         android:id="@+id/item01"
05         android:title="Text+Icon 1"
06         android:icon="@drawable/icon" />
07     <item
08         android:id="@+id/item02"
09         android:title="Text+Icon 2"
10         android:icon="@drawable/icon" />       
11 </menu>

접기

 

 

다음 Icon을 적용한 Option Menu 이다.

 

 

 

B. 단축키 지정


Option menu의 item에는 알파벳 또는 숫자로 단축키를 지정할 수 있다. (Context  Menu는 단축키 지정 불가능) Expanded Menu의 경우 기본으로 "menu+단축키" 정보를 titie 밑에 표시하여 해당 item의 단축키 정보를 알려준다. 반면 Icon Menu영역에서는 기본적으로 단축키 정보가 표시되지 않으며 menu키를 누르고 홀드하면 item title과 단축키 정보를 번갈아 가면서 보여진다.

 

*확인할 사항* (혹시 글을 보시는 분 중 아시는 분이 계시면 뎃글 꼭 부탁 드립니다.)

  • AVD에서 알파벳 단축키는 ALT+단축키 입력으로 입력된다.
  • 숫자 단축키는 12 key (핸드폰 키패드) 키보드를 이용해 입력가능(API Reference의 MenuItem:setNumerticShortkey() 참조) 하다고 나와있는데 AVD에서는 입력 방법을 찾지 못했다.
  • 알파벳 단축키는 단축키 정보를 보여주지만 숫자 단축키는 단축키 정보를 보여주지 않는다.
  • Menu:setQwertyMode(boolean)를 사용해도 변화 없음.

 

자바 코드에서의 설정 예

접기

01 @Override
02 public boolean onCreateOptionsMenu(Menu menu) {
03     boolean result = super.onCreateOptionsMenu(menu);
04      
05     MenuItem item = menu.add(0, 1, 0, "Text+Icon 1");
06         item.setIcon(R.drawable.icon);
07         item.setAlphabeticShortcut('a');
08          
09         menu.add(0, 2, 0, "Text+Icon 2")
10             .setIcon(R.drawable.icon)
11             .setAlphabeticShortcut('b');
12              
13     return result;
14 }

접기

 

 

XML에서의 설정 예

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <item
04         android:id="@+id/item01"
05         android:title="Text+Icon 1"
06         android:icon="@drawable/icon"
07         android:alphabeticShortcut="a" />
08     <item
09         android:id="@+id/item02"
10         android:title="Text+Icon 2"
11         android:icon="@drawable/icon"
12         android:alphabeticShortcut="b" />
13 </menu>

접기

 

 

단축키를 적용한 Option Menu 이다. (Icon Menu의 경우 menu버튼을 홀드 하고 있으면 단축키 정보를 보여준다)

 

 

 

C. Menu group지정


기능, 성격별로 구분된 메뉴 item들을 그룹으로 묶어 자바 코드나 XML문서에서 다음 속성들을 지정 할 수 있다.

  • Menu:setGroupCheckable() / android:checkableBehavior
  • Menu:setGroupVisibable() / android:visible
  • Menu:setGroupEnabled() / android:enabled

 

자바 코드에서의 설정 예

접기

01 @Override
02 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
03      
04     MenuItem item = menu.add(0, 1, 0, "Text+Icon 1");
05     item.setIcon(R.drawable.icon);
06     item.setAlphabeticShortcut('a');
07     item.setChecked(true);
08      
09     menu.add(0, 2, 0, "Text+Icon 2")
10         .setIcon(R.drawable.icon)
11         .setAlphabeticShortcut('b');
12      
13     // parameter 별로 설명하면
14     // 0: 0번 GroupID를 가진 item을 그룹 화
15     // true: 그룹 내 item들을 ckeck가능하게 설절
16     // true: radio 버튼처럼 한 그룹에서 동시에 하나의 item만 check가능하게 설정
17     menu.setGroupCheckable(0, true, true);
18      
19     menu.setGroupVisible(0, true);
20     menu.setGroupEnabled(0, true);
21 }

접기

 

 

XML에서의 설정 예

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <group
04         android:checkableBehavior="single"
05         android:visible="true"
06         android:enabled="true" >
07         <item
08             android:id="@+id/item01"
09             android:title="Text+Icon 1"
10             android:icon="@drawable/icon"
11             android:alphabeticShortcut="a"
12             android:checked="true" />
13         <item
14             android:id="@+id/item02"
15             android:title="Text+Icon 2"
16             android:icon="@drawable/icon"
17             android:alphabeticShortcut="b" />
18     </group>
19 </menu>

접기

 

 

위의 xml을 Activity:onCreateContextMenu에서 inflate 시키면 자바 코드 내부에서 구현한 위 예제와 동일한 결과를 얻는다.

 

 

 

 

4. Menu 사용 이벤트 처리

 

Menu에서 발생하는 item 선택 이벤트는 어떤 메뉴에서 이벤트가 발생했느냐에 따라

다음과 같은 두 개의 callback에서 따로 처리한다.

 

 

A. Option Menu의 item이 발생하는 이벤트 처리


다음과 같은 Activity 클래스가 제공하는 callback 메소드를 오버라이딩하여 이벤트를 처리한다.

public boolean onOptionsItemSelected(MenuItem item)

parameter

item: Option Menu객체 내부에 등록된 MenuItem 인스턴스 중 선택 이벤트를 발생 시킨 MenuItem인스턴스를 전달.

return

true: 본 메소드에서 이벤트가 처리됐음을 뜻함.

false: 본 메소드에서 처리 되지 못한 이벤트를 일반적인 방법(item이 포함한 Runable객체를 call하던가, 적절한 이벤트 handler로 메시지 전송)을 이용해 처리함.

 

 

일반적으로, switch~ case~ 문을 이용하여 선언된 Item id와 인자로 전달된 item인스턴스의 id를 비교 하여 어떤 item인지를 판단 후 그에 맞는 처리 루틴을 구현한다.

switch case 를 이용한 메뉴 사용 이벤트 처리 예

접기

01 @Override
02     public boolean onOptionsItemSelected(MenuItem item) {
03          
04         switch (item.getItemId()) {
05         case ID_COLOR_RED:
06             tv.setTextColor(Color.RED);
07             return true;
08         case ID_COLOR_GREEN:
09             tv.setTextColor(Color.GREEN);
10             return true;
11         case ID_COLOR_BLUE:
12             tv.setTextColor(Color.BLUE);
13             return true;
14         case ID_STYLE_NORMAL:
15             tv.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
16             item.setChecked(true);
17             return true;
18         case ID_STYLE_BOLD:
19             tv.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
20             item.setChecked(true);
21             return true;
22         case ID_STYLE_ITALIC:
23             tv.setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
24             item.setChecked(true);
25             return true;   
26         }
27         return (super.onOptionsItemSelected(item));
28 }

접기

 

 

 

 

 

B. Context Menu의 item이 발생하는 이벤트 처리


Context Menu의 Item은 다음의 Activity 클래스가 제공하는 callback을 오버라이딩 하여 이벤트를 처리한다.

public boolean onContextItemSelected (MenuItem item)

parameter

item: Context Menu객체 내부에 등록된 MenuItem 인스턴스 중 이벤트를 발생 시킨 MenuItem인스턴스를 전달.

return

true: 본 메소드에서 이벤트가 처리됐음을 뜻함.

false: 본 메소드에서 처리 되지 못한 이벤트를 일반적인 방법(item이 포함한 Runable객체를 call하던가, 적절한 이벤트 handler로 메시지 전송)을 이용해 처리함.

 

 

onContextItemSelected(…) 메소드에서도 switch~case~ 명령을 사용해 이벤트를 처리하는 것이 일반적이다.

 

 

 

 

5. Android Menu 예제

그럼 지금까지 설명한 내용을 바탕으로 예제를 파악해보자.

예제는 2개의 view(TextView, ImageView)로 구성된 Activity이며

Activity는 option menu를 제공하고 각 view는 view성경에 맞는 context menu를 제공한다.

 

 

 

A. Menu 예제 1 - Menu:add(…) method이용

 

main.xml

접기

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:orientation="vertical"
04     android:layout_width="fill_parent"
05     android:layout_height="fill_parent"
06     android:gravity="center" >
07     <TextView
08         android:id="@+id/textView" 
09         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="Option / Context 메뉴를\n사용해 보세요"
12         android:textSize="20px"
13         android:gravity="center" />
14     <ImageView
15         android:id="@+id/imageView"
16         android:layout_width="wrap_content"
17         android:layout_height="wrap_content"
18         android:gravity="center"
19         android:paddingTop="50px" />
20 </LinearLayout>

접기

 

MyMenuUsingCode.java

접기

001 package com.holim.test;
002 import android.app.Activity;
003 import android.graphics.Color;
004 import android.graphics.PorterDuff;
005 import android.graphics.Typeface;
006 import android.os.Bundle;
007 import android.view.ContextMenu;
008 import android.view.Menu;
009 import android.view.MenuItem;
010 import android.view.SubMenu;
011 import android.view.View;
012 import android.widget.ImageView;
013 import android.widget.TextView;
014 public class MyMenuUsingCode extends Activity {
015      
016     // Group #
017     public static final int ID_GROUP_TEXT_STYLE     = 1;
018      
019     // text size
020     public static final int ID_SIZE_10SP            = Menu.FIRST+1;
021     public static final int ID_SIZE_20SP            = Menu.FIRST+2;
022     public static final int ID_SIZE_30SP            = Menu.FIRST+3;
023      
024     // text colors
025     public static final int ID_COLOR_RED            = Menu.FIRST+4;
026     public static final int ID_COLOR_GREEN          = Menu.FIRST+5;
027     public static final int ID_COLOR_BLUE           = Menu.FIRST+6;
028      
029     // text Style
030     public static final int ID_STYLE_NORMAL         = Menu.FIRST+7;
031     public static final int ID_STYLE_BOLD           = Menu.FIRST+8;
032     public static final int ID_STYLE_ITALIC         = Menu.FIRST+9;
033      
034     // image size
035     public static final int ID_IMAGE_TINT_NORMAL    = Menu.FIRST+10;
036     public static final int ID_IMAGE_TINT_RED       = Menu.FIRST+11;
037     public static final int ID_IMAGE_TINT_BLUE      = Menu.FIRST+12;
038      
039      
040     TextView tv;
041     ImageView iv;
042      
043     /** Called when the activity is first created. */
044     @Override
045     public void onCreate(Bundle savedInstanceState) {
046         super.onCreate(savedInstanceState);
047         setContentView(R.layout.main);
048          
049         tv = (TextView)findViewById(R.id.textView);
050         iv = (ImageView)findViewById(R.id.imageView);
051          
052         iv.setImageResource(R.drawable.tiger);
053          
054         // tv, iv가 context menu를 제공하도록 설정
055         // view 영역을  터치하고 hold하면(약 2초) context menu 호출
056         registerForContextMenu(tv);
057         registerForContextMenu(iv);
058     }
059      
060     // Option menu에 아이템 채움.
061     // Option menu 호출 시 한번말 실행됨.
062     @Override
063     public boolean onCreateOptionsMenu(Menu menu) {
064         boolean result = super.onCreateOptionsMenu(menu);
065                  
066         SubMenu mTextColor = menu.addSubMenu("Text Color >");
067         mTextColor.add(Menu.NONE, ID_COLOR_RED, 2, "Red");
068         mTextColor.add(Menu.NONE, ID_COLOR_GREEN, 1, "Green");
069         mTextColor.add(Menu.NONE, ID_COLOR_BLUE, 0, "Blue");
070          
071         SubMenu mTextStyle = menu.addSubMenu("Text Style >");
072         mTextStyle.add(ID_GROUP_TEXT_STYLE, ID_STYLE_NORMAL, 0, "Normal")
073             .setChecked(true);
074         mTextStyle.add(ID_GROUP_TEXT_STYLE, ID_STYLE_BOLD, 0, "Bold");
075         mTextStyle.add(ID_GROUP_TEXT_STYLE, ID_STYLE_ITALIC, 0, "Italic");
076         mTextStyle.setGroupCheckable(ID_GROUP_TEXT_STYLE, true, true);
077                  
078         return result;
079     }    
080      
081     // Context menu에 item 채움.
082     // Context menu 호출 시 마다 실행됨.
083     @Override
084     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
085          
086         // context menu를 호출시킨 view에 따라 다른 menu 생성
087         if (v == iv) {
088             menu.add(0, ID_IMAGE_TINT_NORMAL, 0, "Tint 해지");
089             menu.add(0, ID_IMAGE_TINT_RED, 0, "Red tint 적용");
090             menu.add(0, ID_IMAGE_TINT_BLUE, 0, "Blue tint 적용");
091             menu.setHeaderIcon(R.drawable.tiger);
092             menu.setHeaderTitle("ImageView의 Context Menu");
093         }
094         else if (v == tv) {        
095             SubMenu smTextSize = menu.addSubMenu("Text Size 설정 >");
096             smTextSize.add(Menu.NONE, ID_SIZE_10SP, Menu.NONE, "10 scaled pixel");
097             smTextSize.add(Menu.NONE, ID_SIZE_20SP, Menu.NONE, "20 scaled pixel");
098             smTextSize.add(Menu.NONE, ID_SIZE_30SP, Menu.NONE, "30 scaled pixel");
099         }          
100     }
101      
102     // Option menu가 화면에 표시되기 전 항상 호출됨
103     // 한번 초기화된 Option Menu의 내용을 동적으로 바꾸거나 할때 사용.
104     @Override
105     public boolean onPrepareOptionsMenu(Menu menu) {
106         boolean result = super.onPrepareOptionsMenu(menu);
107         return result;
108     }
109      
110     // Option menu item이 선택되었을때 발생한는 event의 handler
111     // 발생한 event가 이 메소드나 super 클래스의 원래 메소드에서 처리 되지 않으면 false리턴
112     @Override
113     public boolean onOptionsItemSelected(MenuItem item) {
114          
115         switch (item.getItemId()) {
116         case ID_COLOR_RED:
117             tv.setTextColor(Color.RED);
118             return true;
119         case ID_COLOR_GREEN:
120             tv.setTextColor(Color.GREEN);
121             return true;
122         case ID_COLOR_BLUE:
123             tv.setTextColor(Color.BLUE);
124             return true;
125         case ID_STYLE_NORMAL:
126             tv.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
127             item.setChecked(true);
128             return true;
129         case ID_STYLE_BOLD:
130             tv.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
131             item.setChecked(true);
132             return true;
133         case ID_STYLE_ITALIC:
134             tv.setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
135             item.setChecked(true);
136             return true;   
137         }
138         return (super.onOptionsItemSelected(item));
139     
140      
141     // Context menu의 item 선택 시 발생하는 event의 handler
142     @Override
143     public boolean onContextItemSelected(MenuItem item) {
144          
145         switch (item.getItemId()) {
146         case ID_SIZE_10SP:
147             tv.setTextSize(10);
148             return true;
149         case ID_SIZE_20SP:
150             tv.setTextSize(20);
151             return true;
152         case ID_SIZE_30SP:
153             tv.setTextSize(30);
154             return true;
155         case ID_IMAGE_TINT_NORMAL:
156             iv.clearColorFilter();
157             return true;
158         case ID_IMAGE_TINT_RED:
159             iv.clearColorFilter();
160             iv.setColorFilter(Color.RED,  PorterDuff.Mode.LIGHTEN);
161             return true;
162         case ID_IMAGE_TINT_BLUE:
163             iv.clearColorFilter();
164             iv.setColorFilter(Color.BLUE,  PorterDuff.Mode.LIGHTEN);
165             return true;
166         }
167         return (super.onOptionsItemSelected(item));
168     }   
169 }

접기

 

 

 

 

B. Menu 예제 2 - XML & MenuInflator 이용

 

main.xml

접기

01 <?xml version="1.0" encoding="utf-8"?>
02 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
03     android:orientation="vertical"
04     android:layout_width="fill_parent"
05     android:layout_height="fill_parent"
06     android:gravity="center" >
07     <TextView
08         android:id="@+id/textView" 
09         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="Option / Context 메뉴를\n사용해 보세요"
12         android:textSize="20px"
13         android:gravity="center" />
14     <ImageView
15         android:id="@+id/imageView"
16         android:layout_width="wrap_content"
17         android:layout_height="wrap_content"
18         android:gravity="center"
19         android:paddingTop="50px" />
20 </LinearLayout>

접기

 

option_menu.xml

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <item
04         android:title="Text Color >" >
05         <menu>
06             <item
07                 android:id="@+id/ID_COLOR_RED"
08                 android:title="Red"
09                 android:orderInCategory="2" />
10             <item
11                 android:id="@+id/ID_COLOR_GREEN"
12                 android:title="Green"
13                 android:orderInCategory="1" />
14             <item
15                 android:id="@+id/ID_COLOR_BLUE"
16                 android:title="Blue"
17                 android:orderInCategory="0" />
18         </menu>
19     </item>
20      
21     <item
22         android:title="Text Style >" >
23         <menu>
24             <group
25                 android:checkableBehavior="single" >
26                 <item
27                     android:id="@+id/ID_STYLE_NORMAL"
28                     android:title="Normal"
29                     android:checked="true" />
30                 <item
31                     android:id="@+id/ID_STYLE_BOLD"
32                     android:title="Bold" />
33                 <item
34                     android:id="@+id/ID_STYLE_ITALIC"
35                     android:title="Italic" />
36             </group>
37         </menu>
38     </item>
39 </menu>

접기


context_menu_tv.xml

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <item
04         android:title="Text Size 설정 > " >
05         <menu
06             <item
07                 android:id="@+id/ID_SIZE_10SP"
08                 android:title="10 scaled pixel" />
09             <item
10                 android:id="@+id/ID_SIZE_20SP"
11                 android:title="20 scaled pixel" />
12             <item
13                 android:id="@+id/ID_SIZE_30SP"
14                 android:title="30 scaled pixel" />
15         </menu>
16     </item>
17 </menu>

접기



context_menu_iv.xml

접기

01 <?xml version="1.0" encoding="utf-8"?>
03     <item
04         android:id="@+id/ID_IMAGE_TINT_NORMAL"
05         android:title="Tint 해지" />
06     <item
07         android:id="@+id/ID_IMAGE_TINT_RED"
08         android:title="Red tint 적용" />
09     <item
10         android:id="@+id/ID_IMAGE_TINT_BLUE"
11         android:title="Blue tint 적용" />
12 </menu>

접기


 

MyMenuUsingXMLInflater

접기

001 package com.holim.test;
002 import android.app.Activity;
003 import android.graphics.Color;
004 import android.graphics.PorterDuff;
005 import android.graphics.Typeface;
006 import android.os.Bundle;
007 import android.view.ContextMenu;
008 import android.view.Menu;
009 import android.view.MenuInflater;
010 import android.view.MenuItem;
011 import android.view.View;
012 import android.widget.ImageView;
013 import android.widget.TextView;
014 public class MyMenuUsingXMLInflater extends Activity {
015      
016     TextView tv;
017     ImageView iv;
018      
019     /** Called when the activity is first created. */
020     @Override
021     public void onCreate(Bundle savedInstanceState) {
022         super.onCreate(savedInstanceState);
023         setContentView(R.layout.main);
024          
025         tv = (TextView)findViewById(R.id.textView);
026         iv = (ImageView)findViewById(R.id.imageView);
027          
028         iv.setImageResource(R.drawable.tiger);
029          
030         // tv, iv가 context menu를 제공하도록 설정
031         // view 영역을  터치하고 hold하면(약 2초) context menu 호출
032         registerForContextMenu(tv);
033         registerForContextMenu(iv);
034     }
035      
036     // Option menu에 아이템 채움.
037     // Option menu 호출 시 한번말 실행됨.
038     @Override
039     public boolean onCreateOptionsMenu(Menu menu) {
040         boolean result = super.onCreateOptionsMenu(menu);
041                  
042         new MenuInflater(this).inflate(R.menu.option_menu, menu);
043                  
044         return result;
045     }    
046      
047     // Context menu에 item 채움.
048     // Context menu 호출 시 마다 실행됨.
049     @Override
050     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
051          
052         // context menu를 호출시킨 view에 따라 다른 menu 생성
053         if (v == iv) {
054             // context_menu_iv.xml을 menu로 inflate
055             getMenuInflater().inflate(R.menu.context_menu_iv, menu); 
056   
057             menu.setHeaderIcon(R.drawable.tiger);
058             menu.setHeaderTitle("ImageView의 Context Menu");
059         }
060         else if (v == tv) {
061             // context_menu_tv.xml을 menu로 inflate
062             getMenuInflater().inflate(R.menu.context_menu_tv, menu);       
063         }
064     }
065      
066     // Option menu가 화면에 표시되기 전 항상 호출됨
067     // 한번 초기화된 Option Menu의 내용을 동적으로 바꾸거나 할때 사용.
068     @Override
069     public boolean onPrepareOptionsMenu(Menu menu) {
070         boolean result = super.onPrepareOptionsMenu(menu);
071         return result;
072     }
073      
074     // Option menu item이 선택되었을때 발생한는 event의 handler
075     // 발생한 event가 이 메소드나 super 클래스의 원래 메소드에서 처리 되지 않으면 false리턴
076     @Override
077     public boolean onOptionsItemSelected(MenuItem item) {
078          
079         switch (item.getItemId()) {
080         case R.id.ID_COLOR_RED:
081             tv.setTextColor(Color.RED);
082             return true;
083         case R.id.ID_COLOR_GREEN:
084             tv.setTextColor(Color.GREEN);
085             return true;
086         case R.id.ID_COLOR_BLUE:
087             tv.setTextColor(Color.BLUE);
088             return true;
089         case R.id.ID_STYLE_NORMAL:
090             tv.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
091             item.setChecked(true);
092             return true;
093         case R.id.ID_STYLE_BOLD:
094             tv.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
095             item.setChecked(true);
096             return true;
097         case R.id.ID_STYLE_ITALIC:
098             tv.setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
099             item.setChecked(true);
100             return true;   
101         }
102         return (super.onOptionsItemSelected(item));
103     
104      
105     // Context menu의 item 선택 시 발생하는 event의 handler
106     @Override
107     public boolean onContextItemSelected(MenuItem item) {
108          
109         switch (item.getItemId()) {
110         case R.id.ID_SIZE_10SP:
111             tv.setTextSize(10);
112             return true;
113         case R.id.ID_SIZE_20SP:
114             tv.setTextSize(20);
115             return true;
116         case R.id.ID_SIZE_30SP:
117             tv.setTextSize(30);
118             return true;
119         case R.id.ID_IMAGE_TINT_NORMAL:
120             iv.clearColorFilter();
121             return true;
122         case R.id.ID_IMAGE_TINT_RED:
123             iv.clearColorFilter();
124             iv.setColorFilter(Color.RED,  PorterDuff.Mode.LIGHTEN);
125             return true;
126         case R.id.ID_IMAGE_TINT_BLUE:
127             iv.clearColorFilter();
128             iv.setColorFilter(Color.BLUE,  PorterDuff.Mode.LIGHTEN);
129             return true;
130         }
131         return (super.onOptionsItemSelected(item));
132     }   
133 }

접기

 

 

두 예제의 구현 방법은 다르지만 완전히 같은 결과를 보여준다.


 

 

 

  예제 프로젝트 소스 다운로드