Custom cut/copy action bar for EditText that shows text selection handles

Mam aplikację, w której chcę być w stanie wyświetlić widok tekstu (lub EditText), który pozwala użytkownikowi wybrać jakiś tekst, a następnie nacisnąć przycisk, aby coś zrobić z tym tekstem. Zaimplementowanie tego w wersjach Androida przed Honeycomb nie jest problemem, ale na Honeycomb i powyżej domyślną akcją długiego naciśnięcia jest pokazanie paska akcji z opcjami Kopiuj/Wytnij/Wklej. Mogę przechwycić długie naciśnięcie, aby pokazać własny pasek akcji, ale wtedy nie wyświetlają się uchwyty wyboru tekstu.

Once I uruchomiłem własny tryb ActionMode jak wyświetlić uchwyty wyboru tekstu?

Oto kod, którego używam do uruchomienia ActionMode, który działa, ale nie ma wyświetlanych uchwytów wyboru tekstu:

public boolean onLongClick(View v) {
    if(actionMode == null)
        actionMode = startActionMode(new QuoteCallback());
    return true;
}

class QuoteCallback implements ActionMode.Callback {

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.quote, menu);
        return true;
    }

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

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch(item.getItemId()) {

        case R.id.quote:
            Log.d(TAG, "Selected menu");
            mode.finish();
            // here is where I would grab the selected text
            return true;
        }
        return false;
    }

    public void onDestroyActionMode(ActionMode mode) {
        actionMode = null;
    }
}
Author: Charles, 2012-10-21

3 answers

Wymyśliłem odpowiedź na własne pytanie; TextView (a więc EditText) ma metodę setCustomSelectionActionModeCallback(), która powinna być używana zamiast startActionMode(). Umożliwia To dostosowanie menu używanego przez TextView do wyboru tekstu. Przykładowy kod:

bodyView.setCustomSelectionActionModeCallback(new StyleCallback());

Gdzie StyleCallback dostosowuje menu wyboru tekstu, usuwając Zaznacz wszystko i dodając kilka akcji stylizacji:

class StyleCallback implements ActionMode.Callback {

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        Log.d(TAG, "onCreateActionMode");
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.style, menu);
        menu.removeItem(android.R.id.selectAll);
        return true;
    }

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

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        Log.d(TAG, String.format("onActionItemClicked item=%s/%d", item.toString(), item.getItemId()));
        CharacterStyle cs;
        int start = bodyView.getSelectionStart();
        int end = bodyView.getSelectionEnd();
        SpannableStringBuilder ssb = new SpannableStringBuilder(bodyView.getText());

        switch(item.getItemId()) {

        case R.id.bold:
            cs = new StyleSpan(Typeface.BOLD);
            ssb.setSpan(cs, start, end, 1);
            bodyView.setText(ssb);
            return true;

        case R.id.italic:
            cs = new StyleSpan(Typeface.ITALIC);
            ssb.setSpan(cs, start, end, 1);
            bodyView.setText(ssb);
            return true;

        case R.id.underline:
            cs = new UnderlineSpan();
            ssb.setSpan(cs, start, end, 1);
            bodyView.setText(ssb);
            return true;
        }
        return false;
    }

    public void onDestroyActionMode(ActionMode mode) {
    }
}

XML dla dodatków do menu to:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/italic"
          android:showAsAction="always"
          android:icon="@drawable/italic"
          android:title="Italic"/>
    <item android:id="@+id/bold"
          android:showAsAction="always"
          android:icon="@drawable/bold"
          android:title="Bold"/>
    <item android:id="@+id/underline"
          android:showAsAction="always"
          android:icon="@drawable/underline"
          android:title="Underline"/>
</menu>
 46
Author: Clyde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-16 10:48:03

Powyższe rozwiązanie jest dobre, jeśli chcesz dostosować opcje na pasku akcji. Ale jeśli chcesz nadpisać pasek akcji kopiuj / wklej itp., poniżej znajduje się kod...

public class MainActivity extends Activity {
    EditText editText;
    private ClipboardManager myClipboard;
    private ClipData myClip;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        editText = (EditText) findViewById(R.id.editText3);

        myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        editText = (EditText) findViewById(R.id.editText3);
        editText.setCustomSelectionActionModeCallback(new Callback() {

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                // TODO Auto-generated method stub

            }

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return true;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                // TODO Auto-generated method stub
                switch (item.getItemId()) {
                case android.R.id.copy:
                    int min = 0;
                    int max = editText.getText().length();
                    if (editText.isFocused()) {
                        final int selStart = editText.getSelectionStart();
                        final int selEnd = editText.getSelectionEnd();

                        min = Math.max(0, Math.min(selStart, selEnd));
                        max = Math.max(0, Math.max(selStart, selEnd));
                    }
                    // Perform your definition lookup with the selected text
                    final CharSequence selectedText = editText.getText()
                            .subSequence(min, max);
                    String text = selectedText.toString();

                    myClip = ClipData.newPlainText("text", text);
                    myClipboard.setPrimaryClip(myClip);
                    Toast.makeText(getApplicationContext(), "Text Copied",
                            Toast.LENGTH_SHORT).show();
                    // Finish and close the ActionMode
                    mode.finish();
                    return true;
                case android.R.id.cut:
                    // add your custom code to get cut functionality according
                    // to your requirement
                    return true;
                case android.R.id.paste:
                    // add your custom code to get paste functionality according
                    // to your requirement
                    return true;

                default:
                    break;
                }
                return false;
            }
        });         
    }    
}
 7
Author: SKG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 07:03:07

Najprostszym sposobem na to jest dodanie linii w głównym stylu motywu, który zdefiniowałeś w znaczniku application z AndroidManifest. Otwórz swój styl motywu i dodaj:

<item name="actionModeBackground">@color/your_color</item>

Lub

<item name="android:actionModeBackground">@color/your_color</item>

Na przykład: Mój styl motywu, który zdefiniowałem:

<style name="AppTheme" parent="AppBaseTheme">

        <item name="calendarViewStyle">@style/Widget.Holo.CalendarView</item>
        <item name="android:actionBarStyle">@style/AppTheme1</item>
        <!-- below is the line you have to add -->
        <item name="android:actionModeBackground">@color/black_actionBar</item>
</style>
 0
Author: Pankaj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-11 08:16:41