상단 앱 바는 현재 화면의 정보와 작업을 표시하기 위해 앱 창 상단을 따라 일관된 위치를 제공합니다.
앱 바의 소유권은 앱의 요구사항에 따라 다릅니다. 프래그먼트를 사용할 때 앱 바는 호스트 활동에서 소유하는 ActionBar
로 또는 프래그먼트 레이아웃 내의 툴바로 구현될 수 있습니다.
모든 화면에서 항상 상단에 있고 화면과 같은 너비의 동일한 앱 바를 사용한다면 활동에서 호스팅하는 테마 제공 작업 모음을 사용합니다. 테마 앱 바를 사용하면 일관된 디자인을 유지할 수 있고 옵션 메뉴와 위로 버튼을 호스팅하는 위치를 제공할 수 있습니다.
여러 화면에서 앱 바의 크기, 배치, 애니메이션을 더 세밀하게 제어하려면 프래그먼트에서 호스팅하는 툴바를 사용하세요. 예를 들어 접기 방식 앱 바 또는 화면 절반 너비에만 걸치고 세로로 중앙에 위치한 앱 바가 필요할 수 있습니다.
상황에 따라 메뉴를 확장하고 사용자 상호작용에 응답하는 등 다른 방식을 사용해야 합니다. 다양한 접근 방식을 이해하여 앱에 가장 적합한 방식을 사용하면 시간을 절약하고 앱이 제대로 작동할 수 있습니다.
이 주제의 예에서는 수정 가능한 프로필이 포함된 ExampleFragment
를 참조합니다. 프래그먼트는 앱 바에서 다음 XML 정의 메뉴를 확장합니다.
<!-- sample_menu.xml -->
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings"
android:title="@string/settings"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_done"
android:icon="@drawable/ic_done"
android:title="@string/done"
app:showAsAction="ifRoom|withText"/>
</menu>
메뉴에는 프로필 화면으로 이동하는 옵션과 프로필 변경사항을 저장하는 옵션 두 가지가 있습니다.
활동 소유 앱 바
앱 바는 호스트 활동에서 소유하는 경우가 거의 대부분입니다. 활동에서 앱 바를 소유하면 프래그먼트가 프래그먼트 생성 중에 호출된 프레임워크 메서드를 재정의하여 앱 바와 상호작용할 수 있습니다.
활동에 등록
앱 바 프래그먼트가 옵션 메뉴를 채우는 데 참여하고 있다고 시스템에 알려야 합니다. 이렇게 하려면 다음 예와 같이 프래그먼트의 onCreate(Bundle)
메서드에서 setHasOptionsMenu(true)
를 호출합니다.
Kotlin
class ExampleFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) } }
Java
public class ExampleFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } }
setHasOptionsMenu(true)
는 프래그먼트가 메뉴 관련 콜백을 수신하려고 한다고 시스템에 알립니다. 클릭과 같은 메뉴 관련 이벤트가 발생하면 이벤트 처리 메서드는 먼저 활동에서 호출된 후 프래그먼트에서 호출됩니다.
그러나 애플리케이션 로직에서 이 순서에 의존하지 마세요. 동일한 활동이 여러 프래그먼트를 호스팅하는 경우 각 프래그먼트가 메뉴 옵션을 제공할 수 있습니다. 이 경우 콜백 순서는 프래그먼트가 추가된 순서에 따라 달라집니다.
메뉴 확장
메뉴를 앱 바의 옵션 메뉴에 병합하려면 프래그먼트에서 onCreateOptionsMenu()
를 재정의합니다. 이 메서드는 현재 앱 바 메뉴와 MenuInflater
를 매개변수로 수신합니다. 메뉴 인플레이터를 사용하여 프래그먼트의 메뉴 인스턴스를 만들어 다음 예와 같이 현재 메뉴에 병합합니다.
Kotlin
class ExampleFragment : Fragment() { ... override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.sample_menu, menu) } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { inflater.inflate(R.menu.sample_menu, menu); } }
그림 2는 업데이트된 메뉴를 보여 줍니다.
클릭 이벤트 처리
옵션 메뉴에 참여하는 모든 활동과 프래그먼트는 터치에 응답할 수 있습니다. 프래그먼트의 onOptionsItemSelected()
는 선택된 메뉴 항목을 매개변수로 수신하고 터치가 사용되었는지 나타내는 불리언 값을 반환합니다. 활동이나 프래그먼트가 onOptionsItemSelected()
에서 true
를 반환하면 참여하는 다른 프래그먼트는 콜백을 수신하지 않습니다.
onOptionsItemSelected()
구현에서 메뉴 항목의 itemId
에서 switch
문을 사용합니다. 선택된 항목이 개발자의 항목이라면 터치를 적절하게 처리하고 true
를 반환하여 클릭 이벤트가 처리된다고 나타냅니다. 선택된 항목이 개발자의 항목이 아니라면 super
구현을 호출합니다. 기본적으로 super
구현은 false
를 반환하여 메뉴 처리를 계속 진행합니다.
Kotlin
class ExampleFragment : Fragment() { ... override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.action_settings -> { // Navigate to settings screen. true } R.id.action_done -> { // Save profile changes. true } else -> super.onOptionsItemSelected(item) } } }
Java
public class ExampleFragment extends Fragment { ... @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: { // Navigate to settings screen. return true; } case R.id.action_done: { // Save profile changes. return true; } default: return super.onOptionsItemSelected(item); } } }
동적으로 메뉴 수정
버튼을 숨기거나 표시하거나, 아이콘을 변경하는 로직은 onPrepareOptionsMenu()
에 배치합니다.
이 메서드는 메뉴가 표시되기 직전에 호출됩니다.
계속해서 이전의 예에서 저장 버튼은 사용자가 수정을 시작할 때까지 표시되지 않아야 하고 사용자가 저장한 후에는 사라져야 합니다. 이 로직을 onPrepareOptionsMenu()
에 추가하면 메뉴가 올바르게 표시됩니다.
Kotlin
class ExampleFragment : Fragment() { ... override fun onPrepareOptionsMenu(menu: Menu){ super.onPrepareOptionsMenu(menu) val item = menu.findItem(R.id.action_done) item.isVisible = isEditing } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onPrepareOptionsMenu(@NonNull Menu menu) { super.onPrepareOptionsMenu(menu); MenuItem item = menu.findItem(R.id.action_done); item.setVisible(isEditing); } }
메뉴를 업데이트해야 하면(예: 사용자가 수정 버튼을 눌러 프로필 정보를 수정하는 경우) 호스트 활동에서 invalidateOptionsMenu()
를 호출하여 시스템에서 onCreateOptionsMenu()
를 호출하도록 요청합니다.
무효화 시 onCreateOptionsMenu()
에서 업데이트를 실행할 수 있습니다. 메뉴가 확장되면 시스템에서는 onPrepareOptionsMenu()
를 호출하고 메뉴를 업데이트하여 프래그먼트의 현재 상태를 반영합니다.
Kotlin
class ExampleFragment : Fragment() { ... fun updateOptionsMenu() { isEditing = !isEditing requireActivity().invalidateOptionsMenu() } }
Java
public class ExampleFragment extends Fragment { ... public void updateOptionsMenu() { isEditing = !isEditing; requireActivity().invalidateOptionsMenu(); } }
프래그먼트 소유 앱 바
앱 화면의 대부분에 앱 바가 필요하지 않거나 한 화면에 다른 화면과는 다른 앱 바가 필요하다면 Toolbar
를 프래그먼트 레이아웃에 추가하면 됩니다. 프래그먼트의 뷰 계층 구조 내 어디라도 Toolbar
를 추가할 수 있지만 일반적으로 화면 상단에 유지합니다. 프래그먼트에서 Toolbar
를 사용하려면 다른 뷰에서와 마찬가지로 ID를 제공하고 프래그먼트에서 ID 참조를 가져옵니다. CoordinatorLayout
동작을 사용하여 툴바에 애니메이션을 적용할 수도 있습니다.
<androidx.appcompat.widget.Toolbar
android:id="@+id/myToolbar"
... />
프래그먼트 소유 앱 바를 사용하는 경우 Toolbar
API를 직접 사용하는 것이 좋습니다. setSupportActionBar()
와 Fragment
메뉴 API를 사용하지 마세요. 활동 소유 앱 바에만 적합합니다.
메뉴 확장
Toolbar
편의 메서드 inflateMenu(int)
는 메뉴 리소스의 ID를 매개변수로 사용합니다. XML 메뉴 리소스를 툴바로 확장하려면 다음 예와 같이 resId
를 이 메서드에 전달합니다.
Kotlin
class ExampleFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... viewBinding.myToolbar.inflateMenu(R.menu.sample_menu) } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { ... viewBinding.myToolbar.inflateMenu(R.menu.sample_menu); } }
또 다른 XML 메뉴 리소스를 확장하려면 새 메뉴의 resId
를 사용하여 메서드를 다시 호출합니다. 새 메뉴 항목이 메뉴에 추가되고 기존 메뉴 항목은 수정되거나 삭제되지 않습니다.
기존 메뉴 세트를 교체하려면 다음 예와 같이 새 메뉴 ID로 inflateMenu(int)
를 호출하기 전에 메뉴를 삭제합니다.
Kotlin
class ExampleFragment : Fragment() { ... fun clearToolbarMenu() { viewBinding.myToolbar.menu.clear() } }
Java
public class ExampleFragment extends Fragment { ... public void clearToolbarMenu() { viewBinding.myToolbar.getMenu().clear() } }
클릭 이벤트 처리
setOnMenuItemClickListener()
메서드를 사용하여 툴바에 직접 OnMenuItemClickListener
를 전달할 수 있습니다. 이 리스너는 사용자가 툴바의 끝에 표시된 작업 버튼이나 관련 오버플로에서 메뉴 항목을 선택할 때 호출됩니다. 선택된 MenuItem
은 리스너의 onMenuItemClick()
메서드에 전달되고 다음 예와 같이 작업을 소비하는 데 사용될 수 있습니다.
Kotlin
class ExampleFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... viewBinding.myToolbar.setOnMenuItemClickListener { when (it.itemId) { R.id.action_settings -> { // Navigate to settings screen. true } R.id.action_done -> { // Save profile changes. true } else -> false } } } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { ... viewBinding.myToolbar.setOnMenuItemClickListener(item -> { switch (item.getItemId()) { case R.id.action_settings: // Navigate to settings screen. return true; case R.id.action_done: // Save profile changes. return true; default: return false; } }); } }
동적으로 메뉴 수정
프래그먼트가 앱 바를 소유하면 다른 뷰와 마찬가지로 런타임에 Toolbar
를 수정할 수 있습니다.
이전의 예에 이어서 설명하자면 저장 메뉴 옵션은 사용자가 수정을 시작할 때까지 표시되지 않아야 하고 옵션을 탭했을 때 다시 사라져야 합니다.
Kotlin
class ExampleFragment : Fragment() { ... fun updateToolbar() { isEditing = !isEditing val saveItem = viewBinding.myToolbar.menu.findItem(R.id.action_done) saveItem.isVisible = isEditing } }
Java
public class ExampleFragment extends Fragment { ... public void updateToolbar() { isEditing = !isEditing; MenuItem saveItem = viewBinding.myToolbar.getMenu().findItem(R.id.action_done); saveItem.setVisible(isEditing); } }
탐색 아이콘 추가
탐색 버튼이 있다면 툴바의 시작 부분에 표시됩니다.
툴바에서 탐색 아이콘을 설정하면 아이콘이 표시됩니다. 다음 예와 같이 사용자가 탐색 버튼을 클릭할 때마다 호출되는 탐색별 onClickListener()
를 설정할 수도 있습니다.
Kotlin
class ExampleFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... myToolbar.setNavigationIcon(R.drawable.ic_back) myToolbar.setNavigationOnClickListener { view -> // Navigate somewhere. } } }
Java
public class ExampleFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { ... viewBinding.myToolbar.setNavigationIcon(R.drawable.ic_back); viewBinding.myToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Navigate somewhere. } }); } }