web-dev-qa-db-fra.com

Barre d'action de coupe / copie personnalisée pour EditText qui affiche les poignées de sélection de texte

J'ai une application où je veux pouvoir montrer un TextView (ou EditText) qui permet à l'utilisateur de sélectionner du texte, puis d'appuyer sur un bouton pour faire quelque chose avec ce texte. L'implémentation de ceci sur Android antérieures à Honeycomb ne posent aucun problème, mais sur Honeycomb et au-dessus de l'action par défaut de longue pression consiste à afficher une barre d'action avec des options Copier/Couper/Coller. Je peux intercepter à long- appuyez sur pour afficher ma propre barre d'action, mais je n'obtiens pas les poignées de sélection de texte affichées.

Une fois que j'ai démarré mon propre ActionMode, comment afficher les poignées de sélection de texte?

Voici le code que j'utilise pour démarrer le ActionMode, qui fonctionne sauf qu'il n'y a pas de poignées de sélection de texte affichées:

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;
    }
}
34
Clyde

J'ai trouvé la réponse à ma propre question; TextView (et donc EditText) a une méthode setCustomSelectionActionModeCallback() qui devrait être utilisée à la place de startActionMode(). Son utilisation permet de personnaliser le menu utilisé par TextView pour la sélection de texte. Exemple de code:

bodyView.setCustomSelectionActionModeCallback(new StyleCallback());

où StyleCallback personnalise le menu de sélection de texte en supprimant Sélectionner tout et en ajoutant des actions de style:

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) {
    }
}

Le XML pour les ajouts de menu est:

<?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>
51
Clyde

La solution ci-dessus est bonne si vous souhaitez personnaliser les options de la barre d'action. Mais si vous voulez remplacer la copie/coller de la barre d'actions, etc., voici le code ...

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;
            }
        });         
    }    
}
9
SKG

La manière la plus simple de le faire est d'ajouter une ligne dans votre style de thème principal que vous avez défini dans votre balise application de AndroidManifest. Ouvrez votre style de thème et ajoutez ce qui suit:

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

OR

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

Par exemple: Mon style de thème que j'ai défini:

<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
Pankaj