Android перехватывает вставку\копирование\вырезание в editText

Как я могу перехватить такого рода события?

Мне нужно добавить некоторую логику, когда пользователь пытается вставить некоторый текст в мой EditText, я знаю, что могу использовать TextWatcher, но эта точка входа мне не подходит, потому что мне нужно перехватывать только в случае вставки, а не каждый раз, когда пользователь нажимает мой EditText,


person and_dev    schedule 20.02.2013    source источник
comment
Хороший вызов. Посмотрите на мой ответ.   -  person Lukas Knuth    schedule 20.02.2013


Ответы (2)


Кажется, с помощью API вы мало что можете сделать: событие вставки Android

Чтение исходного кода вам на помощь!

Я копался в исходном коде Android TextView (EditText — это TextView с некоторой другой конфигурацией) и обнаружил, что меню, используемое для предложения параметров вырезания/копирования/вставки, представляет собой просто модифицированный ContextMenu (источник).

Что касается обычного контекстного меню, View должен создать меню (source), а затем обрабатывать взаимодействие с помощью метода обратного вызова (источник).

Поскольку метод обработки — public, мы можем просто подключиться к нему, расширив EditText и перезаписав метод, чтобы он реагировал на различные действия. Вот пример-реализация:

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;
import android.widget.Toast;

/**
 * An EditText, which notifies when something was cut/copied/pasted inside it.
 * @author Lukas Knuth
 * @version 1.0
 */
public class MonitoringEditText extends EditText {

    private final Context context;

    /*
        Just the constructors to create a new EditText...
     */
    public MonitoringEditText(Context context) {
        super(context);
        this.context = context;
    }

    public MonitoringEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public MonitoringEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
    }

    /**
     * <p>This is where the "magic" happens.</p>
     * <p>The menu used to cut/copy/paste is a normal ContextMenu, which allows us to
     *  overwrite the consuming method and react on the different events.</p>
     * @see <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3_r1/android/widget/TextView.java#TextView.onTextContextMenuItem%28int%29">Original Implementation</a>
     */
    @Override
    public boolean onTextContextMenuItem(int id) {
        // Do your thing:
        boolean consumed = super.onTextContextMenuItem(id);
        // React:
        switch (id){
            case android.R.id.cut:
                onTextCut();
                break;
            case android.R.id.paste:
                onTextPaste();
                break;
            case android.R.id.copy:
                onTextCopy();
        }
        return consumed;
    }

    /**
     * Text was cut from this EditText.
     */
    public void onTextCut(){
        Toast.makeText(context, "Cut!", Toast.LENGTH_SHORT).show();
    }

    /**
     * Text was copied from this EditText.
     */
    public void onTextCopy(){
        Toast.makeText(context, "Copy!", Toast.LENGTH_SHORT).show();
    }

    /**
     * Text was pasted into the EditText.
     */
    public void onTextPaste(){
        Toast.makeText(context, "Paste!", Toast.LENGTH_SHORT).show();
    }
}

Теперь, когда пользователь использует вырезание/копирование/вставку, отображается Toast (конечно, вы можете делать и другие вещи).

Удобно то, что это работает вплоть до Android 1.5, и вам не нужно повторно создавать контекстное меню (как предложено в приведенном выше связанном вопросе), которое сохранит постоянное внешний вид платформы (например, с HTC Sense).

person Lukas Knuth    schedule 20.02.2013
comment
я получил ошибку не могу создать экземпляр класса без пустого конструктора какое решение??? - person Nirav Mehta; 11.07.2014
comment
ну, у класса нет пустого конструктора. вы должны передать ему экземпляр Context (если ваш код находится в действии, вы можете передать его this). - person Lukas Knuth; 11.07.2014
comment
Расширение вашего решения с помощью прослушивателя, чтобы его можно было использовать в качестве компонента Plug&Play. Суть gist.github.com/guillermomuntaner/82491cbf0c88dec560a5 - person GuillermoMP; 18.01.2016
comment
Как получить вставленную составную строку из вставки? - person Zxcv; 26.09.2016
comment
@Pierre, вы могли бы добавить TextWatcher и записать изменения. Если происходит изменение, и вы получаете соответствующее действие вырезания/вставки/копирования, вы можете выяснить, какая часть содержимого изменилась. - person Lukas Knuth; 26.09.2016
comment
Наконец нашел лучшее решение. Я не хочу, чтобы TextWatcher срабатывал каждый раз, когда нажимается буква. Итак, я использовал ClipBoardManager для переопределения вставленного содержимого. Благодаря: stackoverflow.com/ вопросов/6651184/ и developer.android.com/guide /topics/text/copy-paste.html - person Zxcv; 26.09.2016

Есть гораздо более простой способ, хотя и не на 100% надежный.

Добавьте TextChangedListener в свой редактор:

EditText et = (EditText) mView.findViewById(R.id.yourEditText);
et.addTextChangedListener(new TextWatcher() {

  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
     if (count > 2) toast("text was pasted");
  }

  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {

  }

  public void afterTextChanged(Editable s) {
               
  }
});

Если текст меняется более чем на 2 символа, можно считать, что он был вставлен (некоторые смайлики занимают два символа).

Конечно, он не обнаружит вставку, когда пользователь вставит 1 или 2 символа, и ложно сообщит о вставке, если изменение текста было вызвано чем-то другим.

Но для большинства целей он выполняет свою работу ????

person lenooh    schedule 06.04.2016
comment
Это не работает, если ваш текст редактирования ограничен только 1 символом, и вы хотите скопировать несколько текстов редактирования (например, код с 1 et для каждой цифры) - person tiagocarvalho92; 05.07.2019
comment
tiagocarvalho92: да, так написано в описании. - person lenooh; 09.07.2019
comment
Это кажется нормальным. Потому что я бы посмотрел на интеграцию с системой и, возможно, использовал автозаполнение или эту штуку поставщика одноразовых паролей, которая автоматически читает сообщения. Это гораздо лучший пользовательский опыт. Также не помешала бы кнопка «Вставить». В этом сценарии действительно нет причин ограничиваться EditText. - person milosmns; 23.04.2020
comment
Очень умно, это решило мою проблему! - person Bogdan Android; 26.01.2021