Nested Contextual Action Bars

十年热恋 提交于 2019-12-08 12:24:41

问题


I am creating custom contextual action bars (CAB) within a custom WebView.

My requirements are such that selecting a particular option from the first CAB will open a second CAB. This is the end goal:

I have made this happen, but the selection is not working correctly. I know it looks correct, but if the user taps any of the other three icons, this is the result:

If the user touches the selection after pressing any of the four initial icons, the app crashes due to a null pointer exception.

When the user touches the lingering selection after selecting an action, the app tries to access the ActionMode (let's call it firstActionMode) that created the CAB with the icons in order to invalidate/refresh it. However, firstActionMode is destroyed when the CAB with the colors is created, (call that secondActionMode) causing a null pointer exception.


In order to clear away the selection, I have found that calling clearFocus() within onDestroyActionMode(firstActionMode) method does the job just fine.

private class CustomActionModeCallback extends ActionMode.Callback {
    @Override
    public void onDestroyActionMode(ActionMode mode) {
        clearFocus();
    }
}

However, when this is implemented, the selection does not persist when secondActionMode creates its CAB:

Choosing a color from this point actually produces the desired functionality. However, while this "works," it (most unfortunately) does not meet my requirements. I need the selection to remain visible and functional when the CAB created by secondActionMode is shown.


Here is the code for my custom class (WebView) and its nested ActionModes
public class CustomWebView extends WebView {

    private ActionMode.Callback mActionModeCallback;

    @Override
    public ActionMode startActionMode(Callback callback) {
        ViewParent parent = getParent();
        if (parent == null) {
            return null;
        }
        if (callback instanceof HighlightActionModeCallback) {
            mActionModeCallback = callback;
        } else {
            mActionModeCallback = new CustomActionModeCallback();
        }       
        return parent.startActionModeForChild(this, mActionModeCallback);
    }

    private class CustomActionModeCallback implements 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.first_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) {
            // This method is called when the handlebars are moved.
            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.copy:
                // Do stuff
                break;
            case R.id.bookmark:
                // Do stuff
                break;

            case R.id.highlight:
                startActionMode(new HighlightActionModeCallback());
                break;

            case R.id.note:
                // Do stuff
                break;
            default:
                return false;
            }

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

        // Called when the user exits the action mode
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            clearFocus(); // This is commented in the first four screens.
        }
    }

    private class HighlightActionModeCallback implements 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.highlight_colors, 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) {
            // This method is called when the handlebars are moved.
            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) {
            mode.finish(); // Action picked, so close the CAB
            return true;
        }

        // Called when the user exits the action mode
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // Remove the selection highlight and handles.
            clearFocus();
        }
    }

}


How can this be fixed? Any and all help is appreciated.

回答1:


I have now solved this problem; I was over-thinking it. The solution lies not in an ActionMode, but within the menu.

Instead of starting an entirely new ActionMode for the color menu, change the icon menu if the highlighter is selected. Save a reference to the Menu parameter in onCreateActionMode and set a flag of some sort; I'm using a boolean.

private class CustomActionModeCallback implements ActionMode.Callback {

    private boolean highlighterClicked = false;
    private Menu mMenu;

    // Called when the action mode is created; startActionMode() was called
    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        mMenu = menu;
        // Inflate a menu resource providing context menu items
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.first_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) {
        // This method is called when the handlebars are moved.
        MenuInflater inflater = mode.getMenuInflater();
        if (highlighterClicked) {
            menu.clear(); // Remove the four icons
            inflater.inflate(R.menu.highlight_colors, menu); // Show the colors
            return true; // This time we did stuff, so return true
        }
        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) {

        highlighterClicked = false;
        switch (item.getItemId()) {
        case R.id.copy:
            // Do stuff
            break;
        case R.id.bookmark:
            // Do stuff
            break;

        case R.id.highlight:
            highlighterClicked = true;
            onPrepareActionMode(mode, mMenu);
            return true;

        case R.id.note:
            // Do stuff
            break;
        default:
            // Any of the colors were picked
            return true;
        }

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

    // Called when the user exits the action mode
    @Override
    public void onDestroyActionMode(ActionMode mode) {
        clearFocus();
    }
}

The selection highlight and handles stay active and functional, and the color options work as intended.

It is safe to delete the second ActionModeCallback class; it is worthless. Again, way over-thought. :P



来源:https://stackoverflow.com/questions/23096993/nested-contextual-action-bars

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!