Prevent to cancel Action Mode by press back button

2019-01-14 12:37发布

Action mode started by calling getActivity().startActionMode(calback); is automatically canceled after back button pressed. Is possible avoid this behavior? I need to do another operation after back button was pressed in some situation during action mode.

3条回答
唯我独甜
2楼-- · 2019-01-14 13:23

This is an interesting problem. When the ActionMode is active the back key event is consumed internally. The event is not propagated to either onBackPressed() or onKeyUp(int keyCode, KeyEvent event) callbacks.

Fortunately, you can use dispatchKeyEvent(KeyEvent event) which is still called.

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if(mActionModeIsActive) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
           // handle your back button code here
           return true; // consumes the back key event - ActionMode is not finished
        }
    }
    return super.dispatchKeyEvent(event);
}

You might wonder what will be the behavior in case you have a submenu in the ActionMode and you close it with the back key. In this case dispatchKeyEvent() is not called so you can safely use the code.

The above code works also with ActionBarSherlock. The only problem I found is on Android 3.1 device when the native ActionMode is used, in this case the dispatchKeyEvent() is not called. Use ActionBarSherlock's ActionMode to solve it.

查看更多
狗以群分
3楼-- · 2019-01-14 13:32

Create your own Window.Callback and intercept event before it is passed to AppCompatDelegateImplBase.

@Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        //default delegate
        final Window window = getActivity().getWindow();
        mWindowCallbackDelegate = new WindowCallbackDelegate(window.getCallback(), this);
        window.setCallback(mWindowCallbackDelegate);
        return true;
    }

In your own delegate :

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    return myWindowDelegate.dispatchKeyEvent(event) || mOriginalWindowCallback.dispatchKeyEvent(event);
}

When you destroy action mode, restore reference to previous delegate

 @Override
        public void onDestroyActionMode(ActionMode mode) {
        Window.Callback originalWindowCallback = mWindowCallbackDelegate.getOriginalWindowCallback();
        if (originalWindowCallback != null) {
            getActivity().getWindow().setCallback(originalWindowCallback);
        }}

You own delegate signature:

public class WindowCallbackDelegate implements Window.Callback {...}

查看更多
萌系小妹纸
4楼-- · 2019-01-14 13:33

Suggested solutions did not work for me. So I decide to create back event manually. I needed this event in my fragment so I created BaseFragment that all my fragments will extend.

public abstract class BaseFragment extends Fragment {

    private ActionModeState actionModeState = ActionModeState.ITEM_NOT_CLICKED;

    protected enum ActionModeState {
        ITEM_NOT_CLICKED, ITEM_CLICKED
    }

    protected void onActionItemClicked() {
        actionModeState = ActionModeState.ITEM_CLICKED;
    }

    protected void onDestroyActionMode() {
        if (actionModeState == ActionModeState.ITEM_NOT_CLICKED) {
            onActionModeBackPressed();
        } else {
            // reset state
            actionModeState = ActionModeState.ITEM_NOT_CLICKED;
        }
    }

    protected void onActionModeBackPressed() { }

}

Main fragment

public class YourMainFragment extends BaseMapFragment {

    @Override
    public void onActionModeBackPressed() {
        // you code for action mode back button
    }


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

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            YourMainFragment.this.onActionItemClicked();
            ....
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            YourMainFragment.this.onDestroyActionMode();
            ...
        }
    };
查看更多
登录 后发表回答