* Contextual Action Bar란?

 

Contextual Action Bars


A contextual action bar (CAB) is a temporary action bar that overlays the app's action bar for the duration of a particular sub-task. CABs are most typically used for tasks that involve acting on selected data or text.

Contextual action bar shown in Browser and Gmail

The selection CAB appears after a long press on a selectable data item triggers selection mode.

From here the user can:

  • Select additional elements by touching them.
  • Trigger an action from the CAB that applies to all selected data items. The CAB then automatically dismisses itself.
  • Dismiss the CAB via the navigation bar's Back button or the CAB's checkmark button. This removes the CAB along with all selection highlights.

Use CABs whenever you allow the user to select data via long press. You can control the action content of a CAB in order to insert the actions you would like the user to be able to perform.

For more information, refer to the Selection pattern.

 

출처 : Android Developers, http://developer.android.com/intl/ko/design/patterns/actionbar.html

 

한마디로 말해서, 특정 작업을 수행할 경우에 액션 바 위에 일시적으로 덮어씌워지는 새로운 바 입니다.

 

 

이 때, 왼쪽 상단에 done button(v표시)가 생기는데요, 이를 누르거나 취소버튼을 누를경우 Contextual Actionbar가 사라지게 됩니다.

 

여기서 잠깐.. Contextual ActionBar의 코드를 살펴볼게요

 

http://developer.android.com/guide/topics/ui/menus.html#CAB 에 가시면 확인하실 수 있습니다.

 

 

요약하자면, 아래와 같습니다.

 

  1. Implement the ActionMode.Callback interface. In its callback methods, you can specify the actions for the contextual action bar, respond to click events on action items, and handle other lifecycle events for the action mode.
  2. Call startActionMode() when you want to show the bar (such as when the user long-clicks the view).

 

1번에서, CallBack 클래스의 인스턴스를 생성할때 오버라이드를 해주어야 하는 메소드는 다음과 같습니다.

 

public boolean onCreateActionMode(ActionMode mode, Menu menu) : actionmode가 생성될때 (=startActionMode()메소드가 호출될때) 호출됩니다.

public boolean onPrepareActionMode(ActionMode mode, Menu menu)  : actionmode가 보여질때 호출됩니다.

public boolean onActionItemClicked(ActionMode mode, MenuItem item) : actionmode의 menu item이 선택될때 호출됩니다.

public void onDestroyActionMode(ActionMode mode) : actionmode가 종료될때 실행됩니다.

 

이때, done 버튼이나 취소 버튼을 누르면 onDestroyActionMode 메소드가 호출되며 CAB가 사라지게 됩니다.

 

 

이때, 아쉽게도 onBackPressed 메소드와 같이 기존 액티비티 내에서 back button을 인식하는 메소드는 호출되지 않는데다가 button을 터치했거나 back버튼을 눌렀을때 호출되는 onDestroyAcitonMode 메소드에는 둘을 구별할 만한 정보가 입력되지 않습니다.

 

 

done button을 누른것과 취소 버튼을 구분하기 위해 수동으로 키입력을 받아 처리하게 됩니다.

 

즉, dispatchKeyEvent 메소드를 오버라이드 합니다.

 

 

 

 

우선 boolean 형태로 현재 CAB 상태에 있는지 확인하는 변수를 클래스 변수로 생성합니다.

또, onDestroyActionMode 메소드에서 done button을 눌러 종료했는지, back키를 눌러 종료했는지 확인하기 위해 다른 boolean 변수를 추가합니다.

 

 

public class ~~~ extends Activity{

 

boolean actionmode = false;

boolean backpressed = false; // onDestroyActionMode에서 이를 확인하여 true일 경우 done button이 아닌 back키를 누

 

 

}

 

 

CAB를 호출할때 호출될 CallBack 인스턴스를 생성합니다.

Callback actionModeCallBack = new ActionMode.Callback(){

public boolean onCreateActionMode(ActionMode mode, Menu menu){ ... };

public boolean onPrepareActionMode(ActionMode mode, Menu menu) { ... };

public boolean onActionItemClicked(ActionMode mode, MenuItem item){ ... };

public void onDestroyActionMode(ActionMode mode){ ... };

 

}

 

이때, onPrepareActionMode 나 onCreateActionMode 메소드 중 하나에 actionmode임을 알리는 actionmode = true; 명령을 추가합니다.

 

물론 onDestroyActionMode 메소드에는 actionmode = false;를 입력해주시구요..

 

 

이 인스턴스 생성 명령과 별도로, dispatchKeyEvent 메소드를 오버라이드합니다.

 

 

public boolean dispatchKeyEvent(KeyEvent event){
  if(actionmode){                         // actionmode인지 확인(1)
   if(event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP){ // done button/back button 구별(2)
    
    backpressed = true; // back button일 경우 backpressed를 true로 변경(3)
    
   }
  }
  return super.dispatchKeyEvent(event);
 }

 

우선 현재 actionmode인지 확인해야겠죠. 아닐 경우에는 원래의 기능을 처리하게 됩니다.(1번)

맞을 경우에는, 이 터치가 done button을 누른 것인지, back버튼을 누른 것인지 구별하게 됩니다.(2번)

if 문 안의 내용이 true라면 이 key event는 backbutton을 눌렀다 뗀 것이 되겠죠..

false이면 이외의 기능이니 이 역시 원래의 기능을 수행하도록 합니다. 여기에는 done button을 누른 것도 포함되는데, done button을 누른 터치를 정상적으로 수행하면 Callback instance에서는 onDestroyActionMode 메소드가 호출됩니다.

backpressed가 false이니 이는 back button이 눌린게 아니고 done button을 눌렀다고 판단되므로, 해당 기능을 수행하면 됩니다.

 

아래에서 설명을 다시할테니 이해가 안되신다면 아래 내용을 읽어주세요.

 

 

다시 Callback 인스턴스 생성문으로 돌아와서..

 

 

public void onDestroyActionMode(ActionMode mode){

if(backpressed){ // 취소키가 눌렸을때 행동

~~~

 

}

else{ // done button이 눌렸을때 행동

~~~

}

actionmode = false;

backpressed = false;

actionmode = null; // 이것은 CAB를 취소하는 구글의 가이드입니다. ActionMode actionmode = startActionMode(actionModeCallBack); 문으로 CAB를 호출하게 되는데, 이 변수를 null로 만듦으로써 CAB를 취소합니다.

}

 

dispatchKeyEvent 메소드에서, 지금 CAB모드이고 눌린 키가 back 버튼이다! 일때 backpressed를 true로 변경하고, 이외의 기능에는 변화가 없도록 했습니다.

이외의 기능부터 보지요. 어쨌거나 dispatchKeyEvent에서는 해당 키가 눌렸다는 기능을 수행하기 때문에, 모든 기능은 정상적으로 동작하며 우리가 원하는 부분은 done button이 눌렸을때는 어떻게 되느냐입니다.

done button이 눌렸을 때에도 역시 해당 메소드가 기능을 수행하는데요, 이러면 CAB는 onDestroyActionMode메소드를 호출하게 됩니다.(done button이 눌렸음을 인식하므로)

destroy메소드에서, backpressed를 판별할때 당연히 backpressed는 false이죠.(dispatchKeyEvent 메소드에서 true로 변경하지 않았으니까요) 따라서 else 안의 문이 호출됩니다.

 

key event가 back 버튼인 경우에는 backpressed가 true가 되고 해당 키가 눌렸음을 dispatchKeyEvent 메소드가 알립니다.

그러면 CAB가 이것을 받아 onDestroyActionMode를 호출하게 되는데, 이때는 backpressed가 true임으로 backbutton이 눌려 이 메소드가 호출되었음을 알게 됩니다.

 

 

 

test1.png

 

done button이 눌렸을 때

 

 

 

test2.png

 

back button이 눌렸을 때

 

* 소프트 키의 back button 역시 back button으로 인식됩니다.

 

 

 

 

해당 기능은 아래 사이트의 내용을 응용하여 제작되었음을 알려드립니다.

위 내용이 어려우신 분은 아래 사이트를 읽어보시고, 그래도 이해가 안되신다면 댓글을 달아주세요!

http://stackoverflow.com/questions/11725729/prevent-to-cancel-action-mode-by-press-back-button