본문 바로가기

유저 인터페이스

네비게이션 드로어 활용 - (2) 메뉴(액션 아이템)가 있는 프래그먼트 처리

네비게이션 드로어와 프래그먼트를 사용하다 보면, 현재 사용중인 프래그먼트에 해당하는 메뉴(액션 아이템)을 표시해야 할 때가 있습니다. (사실, 앱을 만들다 보면 아주 간단한 앱이 아닌 이상 프래그먼트 별로 각각 다른 메뉴를 제공하는 것이 일반적이죠)


이번 포스트에서는 네비게이션 드로어와 프래그먼트를 사용하면서, 프래그먼트에 포함된 메뉴를 처리하는 방법을 알아보겠습니다.

이전 포스트 (2014/06/02 - 네비게이션 드로어 활용 - (1) 프래그먼트와 연동하기)에 이어서 진행되는 내용이므로, 이전 포스트에서 구현한 내용은 추가로 설명하지 않습니다. 궁금하신 분들은 이전 포스트를 참고해 주세요.


프래그먼트에 메뉴 구현하기


프래그먼트가 소개되지 않았던 예전에는 액티비티에 직접 메뉴를 구현했습니다. 하지만, 프래그먼트가 도입된 후로 액티비티에 직접 메뉴를 구현하는 방법 보단 프래그먼트 내에 메뉴를 구현하고, 액티비티는 프래그먼트의 메뉴를 표시하는 방법을 많이 사용하고 있습니다.


프래그먼트에 메뉴를 추가하는 방법은 액티비티에 메뉴를 추가하는 방법과 동일합니다. 따라서 이전에 액티비티에 메뉴를 구현해 보신 분들이라면 큰 어려움 없이 프래그먼트에 메뉴를 구현할 수 있을 것입니다.


예제 프로젝트를 통해 프래그먼트에 메뉴를 추가하는 절차를 알아보겠습니다. 이전 포스트에서 작성했던 예제에 다음과 같이 메뉴 리소스를 추가합니다. 예제에서는 TextFragment에 웹 검색을 할 수 있는 메뉴 하나를 추가했습니다.


[fragment_text.xml]

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".TextFragment" >
    <item android:id="@+id/action_search"
        android:title="Web search"
        app:showAsAction="always" />
</menu>


다음, TextFragment 클래스 내 코드를 수정합니다. 우선 다음과 같이 메뉴 항목 표시 여부를 설정하는 변수 및 메서드를 추가합니다. 이는 네비게이션 드로어의 열리거나 닫힌 상태에 따라 프래그먼트의 메뉴를 숨기고, 다시 표시하기 위해 필요합니다.


[TextFragment.java]

public class TextFragment extends Fragment {

    boolean showActionItems = true;

    public static TextFragment newInstance() {
        TextFragment fragment = new TextFragment();
        return fragment;
    }

    // ... 중략 ...

    public void showActionItems(boolean show){
        this.showActionItems = show;

    }


메뉴를 표시하기 위해 onPrepareOptionsMenu, onCreateOptionsMenu, 그리고 메뉴 항목을 선택했을 때 처리할 동작을 구현하기 위해 onOptionsItemSelected 메서드를 오버라이드합니다.


onPrepareOptionsMenu() 메서드에선 메뉴 표시 여부(showActionItems) 에 따라 메뉴 표시 상태를 변경해 줍니다. onOptionsItemSelected() 에서는 메뉴 항목을 선택했을 때 'Lorem ipsum'이라는 검색어로 웹 검색을 하도록 구현했습니다. (TextFragment에서 표시하고 있는 텍스트가 'Lorem ipsum' 이라서... :) )


[TextFragment.java]

@Override
public void onPrepareOptionsMenu(Menu menu) {
    super.onPrepareOptionsMenu(menu);

    // Show or hide action item
    menu.findItem(R.id.action_search).setVisible(showActionItems);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()){
        case R.id.action_search:
            startActivity(
                    new Intent(Intent.ACTION_WEB_SEARCH)
                            .putExtra(SearchManager.QUERY, "Lorem ipsum"));
            break;
    }
    return super.onOptionsItemSelected(item);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(R.menu.fragment_text, menu);
}


마지막으로, onCreate() 에 setHasOptionsMenu() 를 추가하여 이 프래그먼트에 메뉴를 포함하고 있다는 것을 액티비티에 알려줍니다.


[TextFragment.java]

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }


액티비티에서 네비게이션 드로어 상태 추적하기


네비게이션 드로어의 상태는 액티비티 내의 ActionBarDrawerToggle에서 추적할 수 있습니다.

다음과 같이 ActionBarDrawerToggle 내 두 메서드 (onDrawerOpened(), onDrawerClosed()) 를 오버라이드 한 후, 각 상태에 따라 프래그먼트 내 메뉴를 보이거나 숨기도록 설정합니다.


프래그먼트 내 메뉴 표시 상태를 설정한 후, supportInvalidateOptionsMenu() (호환성 라이브러리를 사용하지 않을 경우 invalidateOptionsMenu() 사용) 를 호출하면 액티비티 및 액티비티 내 포함된 프래그먼트의 메뉴가 갱신됩니다.


[MainActivity.java]

dtToggle = new ActionBarDrawerToggle(this, dlDrawer, R.drawable.ic_drawer, R.string.app_name, R.string.app_name){
    @Override
    public void onDrawerOpened(View drawerView) {
        super.onDrawerOpened(drawerView);

        // Hide action items
        fragText.showActionItems(false);

        // Refresh action items
        supportInvalidateOptionsMenu();
        //invalidateOptionsMenu();
    }

    @Override
    public void onDrawerClosed(View drawerView) {
        super.onDrawerClosed(drawerView);

        // Show action items
        fragText.showActionItems(true);

        // Refresh action items
        supportInvalidateOptionsMenu();
        //invalidateOptionsMenu();
    }
};


이것으로 모든 구현이 끝났습니다. 예제를 실행하면 다음과 같이 프래그먼트에 추가한 메뉴가 표시되며, 메뉴 항목을 누르면 정상적으로 'Lorem ipsum'의 검색 결과를 보여줍니다.





또한, 네비게이션 드로어를 열면 TextFragment에 포함된 메뉴 항목이 표시되지 않는 것을 확인할 수 있습니다.