본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Android/안드로이드] Menu 에 대한 고급정보.

by 돼지왕 왕돼지 2012. 5. 25.
반응형


http://developer.android.com/guide/topics/ui/menus.html 

- Android 3.0 이상부터는 contextual action mode 라는 것이 생겨서, 선택된 content 에 대한 action 을 조금 다르게 처리해주어야 한다.


- Menu 의 종류는 다음과 같이 3개. Option menu ( 3.0 이상부터는 ActionBar 로 ), Context menu, 그리고 Popup menu 가 있다.


- Menu xml 구성요소는 <menu> <item> <group> 이 있다.


- android:showAsAction 은 action bar 에서 언제 그리고 어떻게 보여질지를 결정하는 attribute.


- menu xml 은 MenuInflater 를 이용하여 inflate.


- submenu는 <item> 하단에 바로 <menu> 를 등록함으로서 가능, submenu 는 또 다른 submenu 를 가질 수 없음.


- Android 3.0 부터는 Actionbar 의 우측에 Optional Menu 가 나타나며, 특정 item 에 대해 Action Bar 에 빼려면 다음 옵션을 주면 된다. android:showAsAction="ifRoom".




- Activity 에도, Fragment 에도 OptionMenu 를 설정했다면, 둘이 ActionBar 에 섞여서 나타난다. Activity 것이 먼저 나오고 Fragment 것이 뒤에 나온다. 여러 Fragment 에서 OptionMenu 를 설정했다면, add 되는 순서대로 나온다. 이 순서는 바굴 수 있는데, <item> android:orderInCategory 옵션을 잘 조정하면 된다.


- HoneyComb ( Android 3.0 ) 이전에는 Menu 버튼을 최초로 누를 때 onCreateOptionMenu() 가 불리며 Menu 를 initialize 하지만, Android 3.0 이상부터는 Action Bar 에 메뉴 표시를 위해 Activity 가 create 되는 시점에 불린다.


- onOptionsItemSelected() 에서 return 값이 중요하다. super 는 default 로 false 를 return 한다. Fragment 에도 option menu 가 있는 경우에는 Activity 의 onOptionsItemSelected() 가 먼저 불리고, return 값이 true 가 될때까지, activity 에 붙은 순서대로 fragment들의 onOptionsItemSelected() 가 호출된다.




- Android 3.0 부터는 XML 에 android:onClick 속성을 추가할 수 있다. 속성값으로는 Activity 에 정의된 함수이름을 기술할 수 있으며, 이 함수는 public 으로 정의되고, MenuItem 을 single parameter 로 받는다. 메뉴가 click 되면 자동으로 이 함수가 callback 으로 불린다.


- 여러개의 Activity 가 같은 Menu 를 공유한다면, onCreateOptionMenu 와 onOptionsMenuSelected 만 구현한 Activity 를 만들고, 그 녀석을 상속시키는 방법이 좋다.


- onCreateOptionsMenu() 는 Menu 최초 생성시에만 호출되고, Runtime 에 Menu 를 바꾸고 싶다면, onPrepareOptionsMenu() 를 구현해주어야 한다. Android 3.0 미만의 버전에서는 메뉴 버튼이 눌릴 때마다 항상 이 함수가 호출되지만, 3.0 이상부터는 Menu 는 항상 보이는 존재이기 때문에, invalidOptionMenu() 를 호출해주어야 onPrepareOptionsMenu() 가 호출된다.


- View의 Focus 유무에 따른 Menu 의 갱신은 위험하다. Touch mode 에서는 focus 를 가질 수 없다. View 에 관련된 메뉴를 제공하고 싶다면 Context메뉴를 사용하라.
 

- Android 3.0 이상부터는 Contextual action mode 란 것이 추가되었는데. contextual action bar 라는 것이 추가되고, 앱이 allow 한다면, 여러개의 item 들에 대해 action 을 한번에 수행할 수 있다.




- Context Menu 는 registerForContextMenu() 를 통해 view 를 등록해줌으로서 가능하다. 만약 ListView 나 GridView 의 모든 Item 을 등록하고 싶다면, ListView 나 GridView 를 전달하면 자동으로 전달이 된다. 


- onCreateContextMenu 에는 Click 된 view 와 함께 MenuInfo 가 함께 전달이 된다. 이 MenuInfo 에는 click 된 item 에 대한 추가 정보가 들어있다. 이건 여러 뷰가 동시에 ContextMenu 를 제공할 때, 유용하게 사용된다.






- Contextual action mode 는 user 가 item 을 선택( view long-click 또는 checkbox 등을 check )함으로서 enable 되고, enable 되면 화면 상단에 contextual action bar 가 나타난다. Contextual Action Mode 가 되면 user 는 여러개의 item 을 동시 선택할 수 있다. ( 제공한다면 ) 반대로 모든 아이템을 deselect 하거나, Back button 을 누르거나, Done 버튼을 눌렀을 때, Contextual Action Mode 는 종료되고, Contextual Action Bar 도 사라진다. 


- Contextual Action Bar 가 일반 Action Bar 의 위치를 점유하긴 하지만, 다른 녀석이다.

- 각 View 에 Contextual Action Bar 등록하기.

 ActionMode.Callback 을 구현하고, Activity.startActionMode( actionModeCallback ) 을 호출해준다. 


private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {


    // Called when the action mode is created; startActionMode() was called

    @Override

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {

        // Inflate a menu resource providing context menu items

        MenuInflater inflater = mode.getMenuInflater();

        inflater.inflate(R.menu.context_menu, menu);

        return true;

    }


    // Called each time the action mode is shown. Always called after 


onCreateActionMode, but

    // may be called multiple times if the mode is invalidated.

    @Override

    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {

        return false; // Return false if nothing is done

    }


    // Called when the user selects a contextual menu item

    @Override

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

        switch (item.getItemId()) {

            case R.id.menu_share:

                shareCurrentItem();

                mode.finish(); // Action picked, so close the CAB

                return true;

            default:

                return false;

        }

    }


    // Called when the user exits the action mode

    @Override

    public void onDestroyActionMode(ActionMode mode) {

        mActionMode = null;

    }

};


someView.setOnLongClickListener(new View.OnLongClickListener() {

    // Called when the user long-clicks on someView

    public boolean onLongClick(View view) {

        if (mActionMode != null) {

            return false;

        }


        // Start the CAB using the ActionMode.Callback defined above

        mActionMode = getActivity().startActionMode(mActionModeCallback);

        view.setSelected(true);

        return true;

    }

});






- ListView 나 GridVIew ( or AbsListVIew 상속한 녀석 )에 Contextual Action 등록하기.


AbsListView.MultiChoiceModeListener 를 구현하여, AbsListView.setMultiChoiceModeListener( multiChoiceModeListener ) 에 등록해준다. AbsListView.setChoiceMode( CHOICE_MODE_MULTIPLE_MODAL ) 도 호출해주어야 한다.


ListView listView = getListView();

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {


    @Override

    public void onItemCheckedStateChanged(ActionMode mode, int position,

                                          long id, boolean checked) {

        // Here you can do something when items are selected/de-selected,

        // such as update the title in the CAB

    }


    @Override

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

        // Respond to clicks on the actions in the CAB

        switch (item.getItemId()) {

            case R.id.menu_delete:

                deleteSelectedItems();

                mode.finish(); // Action picked, so close the CAB

                return true;

            default:

                return false;

        }

    }


    @Override

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {

        // Inflate the menu for the CAB

        MenuInflater inflater = mode.getMenuInflater();

        inflater.inflate(R.menu.context, menu);

        return true;

    }


    @Override

    public void onDestroyActionMode(ActionMode mode) {

        // Here you can make any necessary updates to the activity when

        // the CAB is removed. By default, selected items are deselected/unchecked.

    }


    @Override

    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {

        // Here you can perform updates to the CAB due to

        // an invalidate() request

        return false;

    }

});


- PopupMenu 는 API Level 11 이상부터 사용 가능.
 

public void showPopup(View v) {

    PopupMenu popup = new PopupMenu(this, v);

    MenuInflater inflater = popup.getMenuInflater();

    inflater.inflate(R.menu.actions, popup.getMenu());

    // above two lines can be substituted for following one line if your API level is above 14.

    // PopupMenu.inflate()

    popup.show();

}


- Menu 를 Group하면 setGroupVisible(), setGroupEnabled(), setGroupCheckable() 등을 설정할 수 있어 편하다. Grouping 되어도 다른 menu item 들과 같은 depth 에 있다. groupID 를 통해서 group item 을 일괄처리 할 수 있어 편하다. android:showAsAction="ifRoom" 도 마찬가지로 일괄적으로 적용된다. 


- Option Menu 에 있는 Menu Item 은 checkbox 나 radio button 을 가질 수 없다. 만약 checkable 로 만들고 싶다면, 직접 state 관리도 하고, icon, text 등도 교체해주어야 한다.


- Context Menu 등을 checkable 로 만들기 위해서는 <item> 의 android:checkable 이나, <group> 의 android:checkableBehavior 를 설정해주어야 한다. value 는 single( radio ), all( checkbox ), none 이다. checkable item 을 설정해 준것은 callback 을 부르는 역할밖에 하지 못한다. Radio 나 Checkbox 토글은 직접 구현해주어야 한다.


- 특정 Activity 를 띄우는 Intent 가 있을 경우에만 Menu 를 나오게 하고싶다면, CATEGORY_ALTERNATIVE CATEGORY_SELETED_ALTERNATIVE 를 이용하면 된다. Intent 를 하나 만들고 위 2개의 flag 중 하나 혹은 2개 모두를 setting 한다. Menu.addIntentOptions() 를 호출해주면, 이 intent 를 처리할 수 있는 activity 가 있을 때만 menu item 으로 등록하고 그렇지 않을 경우는 자동으로 등록되지 않는다. 등록될 때, target 이 되는 Activity 의 icon 과 label 이 사용된다.


- CATEGORY_SELECTED_ALTERNATIVE 는 현재 화면에서 선택된 element 에 대한 처리를 할 때 사용되는 녀석이기 때문에 onCreateContextMenu() 에서만 쓰인다.

- 반대로 내가 만드는 Activity 가 다른 App 의 Menu.addIntentOption 에 item 으로 등록될 수 있도록 하려면, Manifest 에 CATEGORY_ALTERNATIVE 와/나 CATEGORY_SELECTED_ALTERNATIVE 를 category 로 filter 에 넣어준다.












반응형

댓글