> Hello World !!!

     

@syaku

안드로이드 메뉴 #2 옵션 메뉴와 컨텍스트 메뉴 그리고 서브메뉴 : Android Menu #2 OptionMenu , ContextMenu And SubManenu

written by Seok Kyun. Choi. 최석균

※ 버전 : Android SDK 2.3.1

이번 포스팅에서는 나머지 옵션 메뉴부분과 컨텍스트 메뉴의 대해서 알아보도록 한다.

2011/06/03 - [개발노트/안드로이드 SDK] - 안드로이드 메뉴 #2 옵션 메뉴와 컨텍스트 메뉴 그리고 서브메뉴 : Android Menu #2 OptionMenu , ContextMenu And SubManenu

※ 소스 이해를 돕기위해 설명이므로, 아래의 소스를 분석할때 참조하자.

[체크 메뉴 항목 관련 메서드]
> boolean onPerpareOptionsMenu (Menu menu)
메뉴가 열릴때마다 호출되는 메서드. onCreateOptionsMenu 는 한번만 호출되기 때문에 메뉴 초기화나 메뉴 정의는 한번 밖에할 수 없다.
만약 실행중에 메뉴를 재정의하고자 할때 onPerpareOtionsMenu 에서 정의하면 된다.

> chechableBehavior 속성
none : 체크를 할 수 없는 단독 명령
all : 체크 박스, 여러 개를 선택할 수 있다.
single : 라디오 박스, 한개의 항목만 선택할 수 있다.

[컨텍스트 메뉴 관련 메서드]
> void Activity.registerForContexMenu (View view)
컨텍스트 메뉴 달기위해 사용하는 메서드
> void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
롱 클릭에 의해 호출되는 메서드
> void onCreateContextMenu (ContextMenu menu)
이름은 같지만 인수가 좀 더 적다. 뷰의 컨텍스트 메뉴를 생성할 때 메서드를 호출한다.
> boolean onContextItemSelected (MenuItem item)
컨텍스트 메뉴가 선택되면 호출되는 메서드




 체크 메뉴 항목

메뉴는 입력받는 장치이지만, 체크나 라디오 그룹 등을 통해 프로그램의 현재 상태를 보여주기도 한다. 단 이기능은 컨텍스트 메뉴와 서브 메뉴에서만 사용할 수 있다. 옵션 메뉴는 명령만 받아 들이며, 상태 표시를 못한다.

이번 어플리케이션의 기능은 메뉴를 선택하고 서브메뉴에서 체크와 라디오 를 선택하면 그에 따르는 속성이 레이아웃 버튼에 적용된다.
그후 버튼에 적용된 속성을 읽어 기존에 선택된 값을 유지할 수 있게 한다.

예를들어, 버튼의 현재 색은 흰색이다. 메뉴를 선택하여 여러 라디오 박스중에 빨간색을 선택하여 버튼 색을 빨간색으로 변경한다.
그리고 다시 메뉴를 선택하게 되면 여러 라디오 박스중에 빨간색 라디오 박스가 기본적으로 체크되게 된다.
onPrepareOptionsMenu 메서드를 사용하여 설정된 기존 값을 유지하게 구성하면 된다.


> layout/main.xml
화면 레이아웃에는 버튼을 하나 생성하였다. 버튼의 글자색은 #ff0000 이며 글자크기는 20px 이다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
<Button
	android:id="@+id/button"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:textColor="#ff0000"
	android:text="버튼"
	android:textSize="20px" />
	    
</LinearLayout>


> res/menu/menucheck.xml
자원에 메뉴 항목을 구성하였다. 서브메뉴라는 메뉴 항목을 추가하고,
큰폰트 메뉴 항목 하나와 레드, 그린, 블루 그룹 메뉴항목을 생성하였다.
checkableBehavior 가 all 인 경우 체크박스가 되고, single 인 경우 라디오박스가 된다.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/submenu" android:title="서브 메뉴">
	<menu>
		<group android:id="@+id/checkable_group" android:checkableBehavior="all">
			<item android:id="@+id/bigfont" android:title="큰폰트" />
		</group>
		<group android:id="@+id/exclusive_checkable_group" android:checkableBehavior="single">
			<item android:id="@+id/red" android:title="레드" android:checked="true" />
			<item android:id="@+id/green" android:title="그린" />
			<item android:id="@+id/blue" android:title="블루" />
		</group>		
	</menu>
</item>	

</menu>


> 자바 소스
서브메뉴의 선택에 따라 화면 레이아웃의 버튼이 변하게 된다.


package com.syaku;

import android.app.Activity;
import android.os.Bundle;
import android.widget.*; // Button
import android.view.*; // Menu
import android.graphics.*; // Color

public class AndroidMenu extends Activity {
    /** Called when the activity is first created. */
	
    Button mBtn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main); // layout/main.xml
        mBtn = (Button) findViewById(R.id.button); // call id
    }
    
    public boolean onCreateOptionsMenu(Menu menu) {
    	super.onCreateOptionsMenu(menu);
    	MenuInflater inflater = getMenuInflater();
    	inflater.inflate(R.menu.menucheck,menu); // menu/menucheck.xml
    	
    	return true;    	
    }
    
    public boolean onPrepareOptionsMenu(Menu menu){
    	// 텍스트 사이즈가 40 인 경우 : 기본 = 20
    	if (mBtn.getTextSize() == 40) {
    		menu.findItem(R.id.bigfont).setChecked(true);
    	} else{
    		menu.findItem(R.id.bigfont).setChecked(false);
    	}
    	
    	// 버튼의 텍스트 색상 : 기본 = #ff0000
    	int color = mBtn.getTextColors().getDefaultColor();
    	
    	// import android.graphics.*; Color
    	if (color == Color.RED) {
    		menu.findItem(R.id.red).setChecked(true);
    	}
    	if (color == Color.GREEN) {
    		menu.findItem(R.id.green).setChecked(true);
    	}
    	if (color == Color.BLUE) {
    		menu.findItem(R.id.blue).setChecked(true);
    	}
    		
    	return true; // 이벤트 종료
    }
    
    public boolean onOptionsItemSelected(MenuItem item) {
    	switch (item.getItemId()) {
    		case R.id.bigfont :
	    		if (item.isChecked()) { // 체크인 경우
	    			mBtn.setTextSize(20); // 텍스트 사이즈 20 변경
	    		} else {
	    			mBtn.setTextSize(40); // 텍스트 사이즈 40 변경
	    		}
	    		return true; // 이벤트 종료
    		case R.id.red :
    			mBtn.setTextColor(Color.RED);
    			return true;
    		case R.id.green :
    			mBtn.setTextColor(Color.GREEN);
    			return true;
    		case R.id.blue :
    			mBtn.setTextColor(Color.BLUE);
    			return true;    			
    		
    	}
    	
    	return false; // 이벤트 유효
    }    
}


 컨텍스트 메뉴

컨텍스트 메뉴는 특정 뷰나 항목에 필요한 명령들만 모아 놓은 메뉴이다. 화면을 롱 클릭하거나, 홈 버튼을 누르고 있으면 화면 중앙에 컨텍스트 메뉴가 열린다. 아래의 어플리케이션은 각 메뉴를 오래 누르고 있거나 커서를 오래 누르고 있을 경우 컨텍스트 메뉴가 열리게 된다.
아래의 소스에 이미지에 문제가 발생하고 있다. 정확한 원인을 찾지 못했다... 그래서 이미지 부분은 주석처리하여 실행하여 테스트해보았다.

> 레이아웃 생성 : /res/layout/main.xml
MyImage는 ImageView 의 서브 클래스이다. XML 문서에서는 패키지 경로를 모두 작성해야 한다.
그리고 이미지를 drewable 폴더에 넣어두자. 이미지명은 아래와 같이 icon 이다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  
  <Button 
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="버튼" />

  <EditText
    android:id="@+id/edittext"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="에디트텍스트" />

	<com.syaku.MyImage
    android:id="@+id/myimage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/icon" />
</LinearLayout>


> 자바 소스
package com.syaku;

import android.app.Activity;
import android.os.Bundle;
import android.widget.*; // Toast,Button
import android.view.*; // Menu
import android.graphics.*; // Color
import android.content.*; //Context
import android.util.*; //AttributeSet

public class AndroidMenu extends Activity {
    /** Called when the activity is first created. */
  
  Button mBtn;
  EditText mEdit;
  MyImage mImage;
  
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main); // layout/main.xml
        
        mBtn = (Button) findViewById(R.id.button);
        registerForContextMenu(mBtn); // 컨텍스트 메뉴임을 지정        
        
        mEdit = (EditText) findViewById(R.id.edittext);
        registerForContextMenu(mEdit);
        
        //mImage = (MyImage) findViewById(R.id.myimage);
        //registerForContextMenu(mImage);
        
     }
  
  public void onCreateContextMenu (ContextMenu menu, View v, 
                               ContextMenu.ContextMenuInfo menuInfo) {
   super.onCreateContextMenu(menu, v, menuInfo);
   
   if (v == mBtn) {
     menu.setHeaderTitle("버튼 메뉴");
     menu.add(0,1,0,"레드");
     menu.add(0,2,0,"그린");
     menu.add(0,3,0,"블루");
     
   }
   
   if (v == mEdit) {
     menu.add(0,4,0,"번역하기");
     menu.add(0,5,0,"필기 인식");	 
   }
   
  }
  
  public boolean onContextItemSelected (MenuItem item) {
    switch (item.getItemId()){
      case 1: mBtn.setTextColor(Color.RED); return true;
      case 2: mBtn.setTextColor(Color.GREEN); return true;
      case 3: mBtn.setTextColor(Color.BLUE); return true;
      case 4: Toast.makeText(this,"번연했다.", Toast.LENGTH_SHORT).show(); return true;
      case 5: Toast.makeText(this,"필기 인식했다.", Toast.LENGTH_SHORT).show(); return true;
      case 100: Toast.makeText(this,"회전했다 치고.", Toast.LENGTH_SHORT).show(); return true;
      case 101: Toast.makeText(this,"크기 변경했다 치고.", Toast.LENGTH_SHORT).show(); return true;
      
    }
    return true;
  }
}

class MyImage extends ImageView {
  public MyImage(Context context) {
    super(context);
  }
  
  public MyImage(Context context, AttributeSet attrs) {
    super(context);
  }
  
  public void onCreateContextMenu(ContextMenu menu) {
    super.onCreateContextMenu(menu);
    
    menu.setHeaderTitle("마이이미지 메뉴");
    menu.add(0,100,0,"이미지 회전");
    menu.add(0,101,0,"크기 변경");
  }
  
}



 부록. 디버깅 및 로그

안드로이드 어플리케이션을 개발하면서 발생하는 문제를 빠르게 해결하기 위한 도구에 대해 알아보도록 하자. 기본적인 개발도구인 이클립스는 좋은 디버깅 환경을 제공하고 있다. 에뮬레이터는 개발용이기 때문에 기본적인 디버깅기능을 제공하고 있지만, 실제 모바일기기에는 디버깅을 하겠다는 매니페스트를 지정하여야 한다.

AndroidManifest.xml 파일을 열어서,
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> 라고 설정하면 된다.

디버깅을 시작하기 전에, 문제가 발생하는 부분을 중단점을 설정하여야 한다. 아래와 같이 파란색원이 처음 찍히는 부분이 중단점이다. 파란색점은 아래의 빨간색 테두리에 떠블 클릭하거나 소스 라인에서 Ctrl + Shift + B 단축키를 이용하면 된다.



중단점을 설정해 놓고 F11(Run/Debug) 키를 누르면 중단점을 만나는 부분에서 어플리케이션을 중단된다.
파란색 화살표가 표시되면 현재 실행중인 지점을 나타내는 것이다.



위 메세지는 이클립스가 디버깅을 위해 디버그 퍼스펙티브로 전환하겠는 지 여부를 물어보는 것이다.
Yes 를 누를 경우 자동으로 퍼스펙티브 화면을 전환된다.

몇가지 단축키를 설명하겠다.
F5 : 메서드 안으로 추척한다.
F6 : 다음 명령문을 실행한다.
F7 : 메서드의 끝까지 실행하고 리턴한다.
F8 : 다음 중단점까지 실행한다.
Ctrl + R : 커서가 있는 지점까지 실행한다.
Ctrl + F2 : 디버깅을 중단한다.

디비깅 툴을 잘 이해하려면 익숙해질때까지 사용하는 방벙뿐일 것 같다.

이젠 소스에서 로그을 출력해보도록 하자. 로그 메서드는 다음과 같다.

출력하는 메서드의 이름에 따라 로그의 수준이 결정된다.
Debug : static int Log.d (String tag, String msg[ , Throwable tr]);
Error : static int Log.d (String tag, String msg[ , Throwable tr]);
Warning : static int Log.d (String tag, String msg[ , Throwable tr]);
Infomation : static int Log.d (String tag, String msg[ , Throwable tr]);
Verbose : static int Log.d (String tag, String msg[ , Throwable tr]);

Verbose 로그는 개발 중에만 컴파일 되며, Debug 로그는 실행 중에는 제거된다.
그 외 로그는 항상 유지된다.

로그 메서드의 인수는 tag: 로그이름 , msg: 로그내용 이다.




Syaku Blog by Seok Kyun. Choi. 최석균.
posted syaku blog


『  Links  

안드로이드프로그래밍정복.1(개정판)SDK2.3진저브레드를적용한안드?
카테고리 컴퓨터/IT > 대학교재
지은이 김상형 (한빛미디어, 2011년)
상세보기


http://syaku.tistory.com