Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

기록장

[안드로이드] ActionBar(액션바) 알아보기 본문

안드로이드

[안드로이드] ActionBar(액션바) 알아보기

edit0 2021. 1. 21. 22:39

액티비티를 새로 생성했을 때 항상 볼 수 있는 액션바, 이 액션바를 활용할 수 있는 여러 방법들을 포스팅하도록 하겠다.

 

프로젝트를 생성하고 액티비티를 보면 액션바에 프로젝트 명이 적혀있을 것이다. 앱 제작하다 보면 이 바를 없애든 활용해서 기능을 추가하든 해야겠다는 생각이 들것이다. 여기에 앱 타이틀, 아이콘, 뷰 컨트롤, 액션 버튼, 오버플로 메뉴 등 여러 항목들로 구성할 수 있다. 

 

기본적으로 다뤄보기

 

액션바는 style.xml 에서도 제어할 수 있고 자바 코드에서도 제어할 수 있다.

 

자바코드에서는 아래 코드로 액션바 객체를 얻을 수 있다.

ActionBar actionBar = getSupportActionBar();

 

객체를 얻었으면 제어를 해야하는데 그에 관한 메소드이다.

 

- setDisplayHomeAsUpEnabled(true): 아이콘을 Up 이미지로 표시 설정
- setDisplayShowCustomEnabled(true): CustomView 표시 설정
- setDisplayShowHomeEnabled(true): 홈 아이콘 표시 설정
- setDisplayShowTitleEnabled(true): 타이틀 문자열 표시 설정
- setDisplayUseLogoEnabled(true): 로고 표시 설정

-> 여기까지는 액션바를 구성하는 요소들 중에 무엇을 보이게 할지 설정하는 것이다.

Ex) 아이콘 올려놓고 이 설정을 해주지 않으면 아이콘이 나오지 않는다.

 

- show(): 액션바 보여주기

- hide(): 액션바 숨기기

- setLogo(int resId): 리소스로 로고 지정

- setLogo(Drawable logo): 이미지 객체로 로고 지정

- setTitle(int resId): 리소스로 타이틀 지정

- setTitle(CharSequence title): 문자열로 타이틀 지정

- setSubtitle(int resId): 리소스로 서브 타이틀 지정

- setSubtitle(CharSequence subtitle): 문자열로 서브 타이틀 지정

- setCustomView(int resId): 리소스로 커스텀 뷰 지정

- setCustomView(View view): 뷰로 커스텀 뷰 지정

 

메소드를 사용하여 본인이 원하는 액션바가 완성되도록 적용하면 된다.

ActionBar actionBar = getSupportActionBar();

actionBar.setDisplayHomeAsUpEnabled(true); //홈 버튼 설정
actionBar.setDisplayShowHomeEnabled(true); //아이콘 표시 설정

actionBar.setIcon(R.mipmap.ic_launcher);
actionBar.setTitle("ActionBar");

아까 위에서 style.xml에서도 액션바 제어가 가능하다고 하였는데 다음과 같은 부분들을 설정해줄 수 있다.

색깔은 style.xml의 colorPrimary의 값을 파란색(#3F51B5)으로 준 것이다.

 

만약 Content 영역 위에 액션바가 있는 것처럼 보여주기 위해서는 다음과 같이 해주면 된다.

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
	<!-- Customize your theme here. -->
	<item name="colorPrimary">#00000000</item>
	<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
	<item name="colorAccent">@color/colorAccent</item>
	<item name="windowActionBarOverlay">true</item>
</style>

 

다음으로, 홈버튼이 눌리면 반응되도록 하는건 onOptionsItemSelected()를 오버라이드해서 사용하는데 메뉴가 나올 때 뒤에서 더 설명하도록 하겠다.

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {

	if(item.getItemId() == android.R.id.home){
		Toast.makeText(getApplicationContext(), "Home as up click", Toast.LENGTH_SHORT).show();
		return true;
	}

	return super.onOptionsItemSelected(item);
}

 

메뉴

 

메뉴를 구현하는데 있어서 xml을 이용한 방법과 자바 코드를 이용한 방법으로 나눌 수 있다.

 

 

- onCreateOptionsMenu(Menu menu): 메뉴가 만들어질 때 최초 한 번 호출, 보통 메뉴가 고정일 경우

- onPrepareOptionsMenu(Menu menu): 메뉴가 화면에 보일 때마다 반복 호출, 메뉴를 상황에 따라 다르게 구성해야 할 경우

 

1. xml을 사용한 방법

 

메뉴 코딩(메뉴 폴더 생성 및 메뉴 xml 파일 생성, 편집) -> 메뉴 파일 등록(onCreateOptionMenu() 메소드 오버라이딩) -> 메뉴 선택 시 작동할 내용 코딩(onOptionsItemSelected() 메소드 오버라이딩)

 

res -> menu -> 메뉴.xml

메뉴 항목들을 만들어준다.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu1"
        android:title="메뉴1"
        android:icon="@mipmap/ic_launcher_round"/>

    <item
        android:id="@+id/menu2"
        android:title="메뉴2"
        android:icon="@drawable/ic_launcher_foreground"/>

    <item
        android:id="@+id/menu3"
        android:title="메뉴3" />
</menu>

 

 

onCreateOptionsMenu()는 앱 실행 시 메뉴의 내용을 xml 파일에서 자동으로 읽어와서 보여준다.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	MenuInflater menuInflater = getMenuInflater();
	menuInflater.inflate(R.menu.menu_xml, menu);

	//아이콘을 보여주기 위한 문단
	try{
		Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", boolean.class);
		method.setAccessible(true);
		method.invoke(menu, true);
	} catch (Exception e){
		Log.i("TAG","Error");
	}
	//setOptionalIconsVisible() 함수를 이용하여 값을 true로 설정하면 아이콘이 표시된다.

	return super.onCreateOptionsMenu(menu);
}

 

onOptionsItemSelected() 메소드는 메뉴를 선택했을 경우 그에 맞는 이벤트를 처리할 수 있다.

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {

	//홈 버튼 눌렸을 경우
	if(item.getItemId() == android.R.id.home){
		Toast.makeText(getApplicationContext(), "Home as up click", Toast.LENGTH_SHORT).show();
		return true;
	}

	//등록한 메뉴 항목들이 눌렸을 경우
	switch (item.getItemId()){
		case R.id.menu1:
			Log.i("TAG","메뉴1 눌림");
			break;
		case R.id.menu2:
			Log.i("TAG","메뉴2 눌림");
			break;
		case R.id.menu3:
			Log.i("TAG","메뉴3 눌림");
			break;
	}

	return super.onOptionsItemSelected(item);
}

 

 

2. 자바 코드만 사용한 방법

 

Inflate를 할 필요가 없다.

 

먼저 메뉴 항목을 만들어준다.

add(int groupId, int itemId, int order, CharSequence title) 중 itemId로 어떤 메뉴 버튼이 눌렸는지 식별한다.

@Override
public boolean onCreateOptionsMenu(Menu menu) {

	MenuItem item1 = menu.add(0,0,0, "메뉴1");
	MenuItem item2 = menu.add(0,1,0,"메뉴2");
	item1.setIcon(R.drawable.ic_launcher_background);
	item2.setIcon(R.mipmap.ic_launcher);

	try{
		Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", boolean.class);
		method.setAccessible(true);
		method.invoke(menu, true);
	} catch (Exception e){
		Log.i("TAG","Error");
	}

	return super.onCreateOptionsMenu(menu);
}

 

메뉴 항목을 선택하면 item.getItemId()에 그에 맞는 itemId가 넘어간다.

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {

	if(item.getItemId() == android.R.id.home){
		Toast.makeText(getApplicationContext(), "Home as up click", Toast.LENGTH_SHORT).show();
		return true;
	}

	if(item.getItemId() == 0){
		Log.i("TAG","메뉴1 눌림");
	}
	else if(item.getItemId() == 1){
		Log.i("TAG","메뉴2 눌림");
	}

	return super.onOptionsItemSelected(item);
}

 

 

서브 메뉴 구성하는 법

 

메뉴를 xml로 구성한 경우

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu1"
        android:title="메뉴1"
        android:icon="@mipmap/ic_launcher_round"/>

    <item
        android:id="@+id/menu2"
        android:title="메뉴2"
        android:icon="@drawable/ic_launcher_foreground"/>

    <item
        android:id="@+id/menu3"
        android:title="메뉴3" />

    <item android:title="서브 메뉴">
        <menu>
            <item
                android:id="@+id/menu4"
                android:title="서브 메뉴1"/>
            <item
                android:id="@+id/menu5"
                android:title="서브 메뉴2"/>
        </menu>
    </item>
</menu>

 

메뉴를 자바로 구성한 경우

@Override
public boolean onCreateOptionsMenu(Menu menu) {

	MenuItem item1 = menu.add(0,0,0, "메뉴1");
	MenuItem item2 = menu.add(0,1,0,"메뉴2");
	item1.setIcon(R.drawable.ic_launcher_background);
	item2.setIcon(R.mipmap.ic_launcher);

	SubMenu subMenu = menu.addSubMenu(0,3,0,"서브 메뉴");
	subMenu.add(0,4,0,"서브 메뉴1");
	subMenu.add(0,5,0,"서브 메뉴2");

	try{
		Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", boolean.class);
		method.setAccessible(true);
		method.invoke(menu, true);
	} catch (Exception e){
		Log.i("TAG","Error");
	}

	return super.onCreateOptionsMenu(menu);
}

 

컨텍스트 메뉴

 

컨텍스트 메뉴는 일반 메뉴와 달리 뷰를 길게 누를 때 보이는 메뉴이다. 그래서 뷰를 등록해주어야 사용할 수 있다.

 

1. xml을 사용한 방법

 

메뉴 코딩(메뉴 폴더 생성 및 위젯의 메뉴 xml 파일 생성, 편집) -> 메뉴를 사용할 위젯 등록(onCreate() 안에 registerForContextMenu()로 등록) -> 메뉴 파일 등록(onCreateContextMenu() 메소드 오버라이딩) -> 메뉴 선택 시 동작할 내용 코딩(onContextItemSelected() 메소드 오버라이딩)

 

위에 있는 res -> menu -> 메뉴.xml을 그대로 사용한다. 그럼 메뉴 코딩은 됐다.

 

다음 뷰를 등록해준다.

LinearLayout linearLayout = findViewById(R.id.linearlayout);
registerForContextMenu(linearLayout);

 

onCreateContextMenu() 메소드 내에서 사용할 메뉴를 연결해준다.

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
	super.onCreateContextMenu(menu, v, menuInfo);

	MenuInflater menuInflater = getMenuInflater();
	if(v == linearLayout){
		menu.setHeaderTitle("컨텍스트 메뉴");
		menuInflater.inflate(R.menu.menu_xml, menu); //menu_xml.xml에 연결
	}

}

 

onContextItemSelected() 메소드는 메뉴 선택 시 발생할 이벤트를 정의한다.

@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
	switch (item.getItemId()) {
		case R.id.menu1:
			Log.i("TAG", "메뉴1 눌림");
			break;

		case R.id.menu2:
			Log.i("TAG", "메뉴2 눌림");
			break;

		case R.id.menu3:
			Log.i("TAG", "메뉴3 눌림");
			break;
	}

	return super.onContextItemSelected(item);
}

 

2. 자바 코드만 사용한 방법

 

다음 뷰를 등록해준다.

LinearLayout linearLayout = findViewById(R.id.linearlayout);
registerForContextMenu(linearLayout);

 

onCreateContextMenu() 메소드 오버라이드

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
	super.onCreateContextMenu(menu, v, menuInfo);

	MenuItem item1 = menu.add(0,0,0, "메뉴1");
	MenuItem item2 = menu.add(0,1,0,"메뉴2");
	item1.setIcon(R.drawable.ic_launcher_background);
	item2.setIcon(R.mipmap.ic_launcher);

	SubMenu subMenu = menu.addSubMenu(0,3,0,"서브 메뉴");
	subMenu.add(0,4,0,"서브 메뉴1");
	subMenu.add(0,5,0,"서브 메뉴2");

	try{
		Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", boolean.class);
		method.setAccessible(true);
		method.invoke(menu, true);
	} catch (Exception e){
		Log.i("TAG","Error");
	}
}

 

onContextItemSelected() 메소드 오버라이드

@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
	if(item.getItemId() == 0){
		Log.i("TAG","메뉴1 눌림");
	}
	else if(item.getItemId() == 1){
		Log.i("TAG","메뉴2 눌림");
	}

	return super.onContextItemSelected(item);
}

 

Action Button

 

메뉴보다 조금 더 자주 사용되고 중요도가 높다고 판단되는 항목들을 밖으로 빼서 설정해주는 것이다.

메뉴와 마찬가지로 res -> menu -> 파일.xml로 만들어 이 파일에 보여질 항목들을 만들어주어야 한다. 

 

메뉴 속성에 관한 메소드

 

- never: 기본값이며 showAsAction을 선언하지 않은 경우, 항상 오버플로 메뉴로 구성

- always: 항상 액션 버튼으로 구성

- ifRoom: ActionBar에 아이콘이 올라갈 공간이 있으면 액션 버튼으로 나타내고, 그렇지 않으면 오버플로 메뉴로 나타남. (자동 판단)

- withText: 아이콘과 더불어 문자열이 함께 보이게 하는 설정이지만 문자열이 나타날 공간이 없다면 문자열이 나타나지 않음. 대부분 스마트폰에서는 문자열이 함께 출력되지 않음

 

메뉴 항목을 만들어준다.

위에 메뉴와는 다르게 xmlns:app="http://schemas.android.com/apk/res-auto"를 추가해주고 app:showAsAction 속성을 추가해준다.

네임스페이스명이 android가 아니라 app인 이유는 액션바는 추가된 개념으로 호환성 문제가 있기 때문이다.

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

    <item
        android:id="@+id/menu1"
        android:icon="@drawable/ic_launcher_foreground"
        app:showAsAction = "always"
        android:title="메뉴1" />

    <item
        android:id="@+id/menu2"
        android:icon="@mipmap/ic_launcher"
        app:showAsAction="always"
        android:title="메뉴2"/>

</menu>

 

onCreateOptionsMenu() 메소드, 메뉴와 똑같이 해준다.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	MenuInflater menuInflater = getMenuInflater();
	menuInflater.inflate(R.menu.action_button_menu, menu);

	return super.onCreateOptionsMenu(menu);
}

 

onOptionsItemSelected 메소드도 메뉴와 동일하다.

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {

	switch (item.getItemId()) {
		case R.id.menu1:
			Log.i("TAG", "메뉴1 눌림");
			break;

		case R.id.menu2:
			Log.i("TAG", "메뉴2 눌림");
			break;
	}

	return super.onOptionsItemSelected(item);
}

 

Action View

 

액션뷰는 액션바에서 제공되는 뷰로 개발자가 직접 준비하지 않고 액션바에서 제공하는 뷰를 그대로 이용할 수 있어서 편리하다. 대표적인 뷰인 SearchView는 사용자 검색 기능을 제공할 때 유용하게 쓰인다. 

 

 

메뉴.xml

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

    <item
        android:id="@+id/menu1"
        android:icon="@mipmap/ic_launcher"
        android:title="Search"
        app:actionViewClass="android.widget.SearchView"
        app:showAsAction="always"/>
    
</menu>

 

onCreateOptionsMenu() 메소드

@Override
public boolean onCreateOptionsMenu(Menu menu) {
	MenuInflater menuInflater = getMenuInflater();
	menuInflater.inflate(R.menu.actionview_searchview, menu);

	MenuItem menuItem = menu.findItem(R.id.menu1); //id 값으로 MenuItem 객체 획득
	SearchView searchView = (SearchView)menuItem.getActionView(); //MenuItem에 포함된 SearchView 객체 획득
	searchView.setQueryHint(getResources().getString(R.string.app_name)); //검색 힌트 문자열 지정
	searchView.setOnQueryTextListener(queryTextListener); //사용자 검색어 입력 이벤트 등록

	return super.onCreateOptionsMenu(menu);
}

 

핸들러 정의

//사용자 검색 이벤트 핸들러
private SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
	@Override
	public boolean onQueryTextSubmit(String query) { //입력한 검색어가 매개변수로 전달된다.
	//키보드에서 검색 버튼이 눌린 순간의 이벤트 호출

		Log.i("TAG","onQueryTextSubmit() 호출됨 / " + query );

	return false;
	}

	@Override
	public boolean onQueryTextChange(String newText) {
	//검색 글이 한 자 한 자 입력 되는 순간마다 호출

		Log.i("TAG","onQueryTextChange() 호출됨 / " + newText );

	return false;
	}
};

 

로그로 어떻게 돌아가는지 확인해볼 수 있다.

 

 

감사합니다.

 

 

참고: 깡샘의 안드로이드 프로그래밍