기록장
[안드로이드] ActionBar(액션바) 알아보기 본문
액티비티를 새로 생성했을 때 항상 볼 수 있는 액션바, 이 액션바를 활용할 수 있는 여러 방법들을 포스팅하도록 하겠다.
프로젝트를 생성하고 액티비티를 보면 액션바에 프로젝트 명이 적혀있을 것이다. 앱 제작하다 보면 이 바를 없애든 활용해서 기능을 추가하든 해야겠다는 생각이 들것이다. 여기에 앱 타이틀, 아이콘, 뷰 컨트롤, 액션 버튼, 오버플로 메뉴 등 여러 항목들로 구성할 수 있다.
기본적으로 다뤄보기
액션바는 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;
}
};
로그로 어떻게 돌아가는지 확인해볼 수 있다.
감사합니다.
참고: 깡샘의 안드로이드 프로그래밍
'안드로이드' 카테고리의 다른 글
[안드로이드] 내부(Internal), 외부(External) 저장소, File read/write (0) | 2021.01.20 |
---|---|
[안드로이드] 리소스(Resource) (0) | 2021.01.20 |
[안드로이드] Retrofit2(레트로핏2) 통신 / 오픈 API, 데이터베이스와 데이터 주고 받기 (0) | 2021.01.19 |
[안드로이드] 소리(시스템 효과음), 진동 울리기 (0) | 2021.01.18 |
[안드로이드] GridLayout(그리드 레이아웃) (0) | 2021.01.18 |