Как отключить копирование / вставку из / в EditText


131

В моем приложении есть экран регистрации, где я не хочу, чтобы пользователь мог копировать / вставлять текст в EditTextполе. Я установил для onLongClickListenerкаждого из них, EditTextчтобы контекстное меню, показывающее метод копирования / вставки / ввода и другие параметры, не отображалось. Таким образом, пользователь не сможет копировать / вставлять в поля редактирования.

 OnLongClickListener mOnLongClickListener = new OnLongClickListener() {

        @Override
        public boolean onLongClick(View v) {
            // prevent context menu from being popped up, so that user
            // cannot copy/paste from/into any EditText fields.
            return true;
        }
    };

Но проблема возникает, если пользователь включил стороннюю клавиатуру, отличную от стандартной для Android, которая может иметь кнопку для копирования / вставки или может отображать то же контекстное меню. Итак, как мне отключить копирование / вставку в этом сценарии?

Пожалуйста, дайте мне знать, есть ли другие способы скопировать / вставить. (и, возможно, как их отключить)

Любая помощь будет оценена.


Если операция «вставки» выполняется из IME, у вас нет стандартного способа отличить ее от обычных нажатий клавиш. Одна из идей, которую стоит попробовать, - это измерить время между появлением каждого персонажа, и если время слишком мало, то символы приходят из операции «вставки».
BitBank

вроде грязное решение! хотя стоит посмотреть.
rDroid

1
use android: longClickable = "false"
Азай Гупта

Ответы:


112

Если вы используете API уровня 11 или выше, вы можете запретить отображение контекстных меню для копирования, вставки, вырезания и пользовательских контекстных меню.

edittext.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

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

            public void onDestroyActionMode(ActionMode mode) {                  
            }

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

            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                return false;
            }
        });

Возврат false из onCreateActionMode (ActionMode, Menu) предотвратит запуск режима действия (действия Select All, Cut, Copy и Paste).


1
как насчет уровня API ниже 13?
Джонатан

1
Не понимаю ни одного комментария, этот образец работает api11 +, pre-api11 не было копирования и вставки IIRC
scottyab

29
У меня не работает. Кнопка вставки появится при нажатии на синий индикатор курсора.
недействителен

8
У меня тоже не работает. При двойном нажатии отображается меню копипаста.
Android Killer

это больше не работает на android 6.0, проверьте этот ответ stackoverflow.com/questions/27869983/…
has19

132

Лучший способ - использовать:

etUsername.setLongClickable(false);

58
Или просто в xml android:longClickable="false":)
lomza

19
При нажатии на синий индикатор курсора появится кнопка «Вставить».
недействителен

16
Это, безусловно, предотвратит длительное нажатие на представление, но элементы управления редактированием также могут быть запрошены двойным нажатием на текст, что означает, что это решение не является полным. Имейте это в виду для своих целей.
Кевин Грант

1
Кроме того, сочетания клавиш все еще могут работать (Ctrl + C) с внешней клавиатурой.
Олег Васкевич

Это не работает с Ice Cream Sandwich, потому что параметры буфера обмена можно открыть двойным касанием текста, а также долгим нажатием.
Пол Винц,

44

Вы можете сделать это, отключив долгое нажатие EditText

Чтобы реализовать это, просто добавьте следующую строку в xml -

android:longClickable="false"

6
Проблема заключалась в том, что у моего пользователя приложения есть сторонняя клавиатура с кнопкой копирования и вставки.
rDroid

3
другая проблема в том, что вы можете выделить текст двойным нажатием, и он снова показывает копирование / вставку
Никола

36

Я могу отключить функцию копирования и вставки следующим образом:

textField.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
        return false;
    }

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

    public boolean onActionItemClicked(ActionMode actionMode, MenuItem item) {
        return false;
    }

    public void onDestroyActionMode(ActionMode actionMode) {
    }
});

textField.setLongClickable(false);
textField.setTextIsSelectable(false);

Надеюсь, это сработает для вас ;-)


Это то же самое решение, к которому я пришел, основываясь на других ответах выше. Это должно быть отмечено как правильное решение, поскольку оно обрабатывает крайние случаи, в
отличие

2
Эта опция блокирует копию, но вы все равно можете вставить, щелкнув курсор.
Мехул Канзария

12

вот лучший способ отключить вырезанную копию пасты работы editText во всех версиях

if (android.os.Build.VERSION.SDK_INT < 11) {
        editText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {

            @Override
            public void onCreateContextMenu(ContextMenu menu, View v,
                    ContextMenuInfo menuInfo) {
                // TODO Auto-generated method stub
                menu.clear();
            }
        });
    } else {
        editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

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

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

            }

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

            public boolean onActionItemClicked(ActionMode mode,
                    MenuItem item) {
                // TODO Auto-generated method stub
                return false;
            }
        });
    }

Это работает для меня, я просто должен был добавить @TargetApi (Build.VERSION_CODES.HONEYCOMB)
Sheepdogsheep

11

В дополнение к setCustomSelectionActionModeCallback и отключенным решениям с длительным щелчком необходимо предотвратить появление меню PASTE / REPLACE при щелчке маркера выделения текста, как показано на изображении ниже:

Ручка выделения текста с меню вставки

Решение заключается в том, чтобы предотвратить появление меню PASTE / REPLACE в show()методе (недокументированного) android.widget.Editorкласса. Перед появлением меню выполняется проверка if (!canPaste && !canSuggest) return;. Два метода, которые используются в качестве основы для установки этих переменных, находятся в EditTextклассе:

Более полный ответ доступен здесь .


Это ПРАВИЛЬНОЕ и ПОЛНОЕ решение
FireZenk

В некоторых устройствах вместо «Вставить буфер обмена» видна опция, действует только как вставка. Я проверил ссылки, но могу предотвратить вставку, но не буфер обмена. любая идея ?
Richa

11

Котлинское решение:

fun TextView.disableCopyPaste() {
    isLongClickable = false
    setTextIsSelectable(false)
    customSelectionActionModeCallback = object : ActionMode.Callback {
        override fun onCreateActionMode(mode: ActionMode?, menu: Menu): Boolean {
            return false
        }

        override fun onPrepareActionMode(mode: ActionMode?, menu: Menu): Boolean {
            return false
        }

        override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {
            return false
        }

        override fun onDestroyActionMode(mode: ActionMode?) {}
    }
}

Затем вы можете просто вызвать этот метод на своем TextView:

override fun onCreate() {
    priceEditText.disableCopyPaste()
}

1
Привет, я использую этот подход, но получаю сообщение Type mismatchоб ошибке с этим описанием Required:ActionMode.Callback! Found: в этой части object: ActionMode.Callback. Есть идеи, почему это может не работать?
Абдул Матин

8

Используя другие решения, API 26 (Oreo) по-прежнему показывал дескриптор курсора одним нажатием на введенный текст, после чего можно было отобразить меню. Только комбинация решений может решить мою проблему.

public class CustomEditText extends EditText {

    public CustomEditText(Context context) {
        super(context);
        init();
    }

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        this.setCustomSelectionActionModeCallback(new BlockedActionModeCallback());
        this.setLongClickable(false);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            this.setInsertionDisabled();
        }
        return super.onTouchEvent(event);
    }

    /**
    * This method sets TextView#Editor#mInsertionControllerEnabled field to false
    * to return false from the Editor#hasInsertionController() method to PREVENT showing
    * of the insertionController from EditText
    * The Editor#hasInsertionController() method is called in  Editor#onTouchUpEvent(MotionEvent event) method.
    */
    private void setInsertionDisabled() {
        try {
            Field editorField = TextView.class.getDeclaredField("mEditor");
            editorField.setAccessible(true);
            Object editorObject = editorField.get(this);

            Class editorClass = Class.forName("android.widget.Editor");
            Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
            mInsertionControllerEnabledField.setAccessible(true);
            mInsertionControllerEnabledField.set(editorObject, false);
        }
        catch (Exception ignored) {
            // ignore exception here
        }
    }

    @Override
    public boolean isSuggestionsEnabled() {
        return false;
    }

    private class BlockedActionModeCallback implements ActionMode.Callback {
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            return false;
        }

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

        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        public void onDestroyActionMode(ActionMode mode) {
        }
    }
}

5

Если вы не хотите отключать долгий щелчок, потому что вам нужно выполнять некоторые функции при долгом щелчке, чем возврат true - лучший вариант для этого.

Ваш длинный щелчок edittext будет таким.

edittext.setOnLongClickListener(new View.OnLongClickListener() {
      @Override
      public boolean onLongClick(View v) {
            //  Do Something or Don't
            return true;
      }
});

Согласно документации, возврат «True» будет указывать на то, что был обработан длинный щелчок, поэтому нет необходимости выполнять операции по умолчанию.

Я тестировал это на уровне API 16, 22 и 25. Он отлично работает для меня. Надеюсь, это поможет.


1
Хороший. Как вариант, просто установите android:longClickable="false"в XML
Алексей Семенюк

3

https://github.com/neopixl/PixlUI предоставляет EditTextметод

myEditText.disableCopyAndPaste(),

И он работает на старом API


1
Это делает то же самое, что и полурешение, предоставленное stackoverflow.com/a/22756538/3063884 . См. Код: github.com/neopixl/PixlUI/blob/master/Library/src/com/neopixl/… ... Этот подход по-прежнему не мешает обработчику выделения текста показывать "PASTE", если текст в буфере обмена ,
CJBS

3

Вот хитрость, чтобы отключить всплывающее окно «вставить». Вам нужно переопределить EditTextметод:

@Override
public int getSelectionStart() {
    for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
        if (element.getMethodName().equals("canPaste")) {
            return -1;
        }
    }
    return super.getSelectionStart();
}

То же самое можно сделать и для других действий.


Можете ли вы сказать об отключении буфера обмена
Richa

3

Я протестировал это решение, и оно работает

    mSubdomainEditText.setLongClickable(false);
    mSubdomainEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

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

      public void onDestroyActionMode(ActionMode mode) {
      }

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

      public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        return false;
      }
    });

1

Прочтите буфер обмена, сравните ввод и время, когда ввод «набран». Если в буфере обмена есть тот же текст, но он слишком быстрый, удалите вставленный ввод.


1

@Zain Ali, ваш ответ работает с API 11. Я просто хотел предложить способ сделать это и с API 10. Поскольку мне приходилось поддерживать API моего проекта в этой версии, я постоянно играл с функциями, доступными в 2.3.3, и получил возможность это сделать. Я поделился фрагментом ниже. Я протестировал код, и он работал у меня. Я сделал этот фрагмент в срочном порядке. Не стесняйтесь улучшать код, если есть какие-либо изменения, которые можно сделать ..

// A custom TouchListener is being implemented which will clear out the focus 
// and gain the focus for the EditText, in few milliseconds so the selection 
// will be cleared and hence the copy paste option wil not pop up.
// the respective EditText should be set with this listener 
// tmpEditText.setOnTouchListener(new MyTouchListener(tmpEditText, tmpImm));

public class MyTouchListener implements View.OnTouchListener {

    long click = 0;
    EditText mEtView;
    InputMethodManager imm;

    public MyTouchListener(EditText etView, InputMethodManager im) {
        mEtView = etView;
        imm = im;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            long curr = System.currentTimeMillis();
            if (click !=0 && ( curr - click) < 30) {

                mEtView.setSelected(false);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mEtView.setSelected(true);
                        mEtView.requestFocusFromTouch();
                        imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
                    }
                },25);

            return true;
            }
            else {
                if (click == 0)
                    click = curr;
                else
                    click = 0;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mEtView.requestFocusFromTouch();
                        mEtView.requestFocusFromTouch();
                        imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
                    }
                },25);
            return true;
            }

        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            mEtView.setSelected(false);
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mEtView.setSelected(true);
                    mEtView.requestFocusFromTouch();
                    mEtView.requestFocusFromTouch();
                    imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
                }
            },25);
            return true;
        }
        return false;
    }

1

решение очень простое

public class MainActivity extends AppCompatActivity {

EditText et_0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    et_0 = findViewById(R.id.et_0);

    et_0.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            //to keep the text selection capability available ( selection cursor)
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            //to prevent the menu from appearing
            menu.clear();
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {

        }
    });
   }
}

--------> предварительный просмотр <---------


1

Попробуйте следовать классу клиентов для преобладающего копирования и вставки Edittext

public class SegoeUiEditText extends AppCompatEditText {
private final Context context;


@Override
public boolean isSuggestionsEnabled() {
    return false;
}
public SegoeUiEditText(Context context) {
    super(context);
    this.context = context;
    init();
}

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

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


private void setFonts(Context context) {
    this.setTypeface(Typeface.createFromAsset(context.getAssets(), "Fonts/Helvetica-Normal.ttf"));
}

private void init() {

        setTextIsSelectable(false);
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        this.setLongClickable(false);

}
@Override
public int getSelectionStart() {

    for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
        if (element.getMethodName().equals("canPaste")) {
            return -1;
        }
    }
    return super.getSelectionStart();
}
/**
 * Prevents the action bar (top horizontal bar with cut, copy, paste, etc.) from appearing
 * by intercepting the callback that would cause it to be created, and returning false.
 */
private class ActionModeCallbackInterceptor implements ActionMode.Callback, android.view.ActionMode.Callback {
    private final String TAG = SegoeUiEditText.class.getSimpleName();

    public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; }
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; }
    public void onDestroyActionMode(ActionMode mode) {}

    @Override
    public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
        return false;
    }

    @Override
    public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
        menu.clear();
        return false;
    }

    @Override
    public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
        return false;
    }

    @Override
    public void onDestroyActionMode(android.view.ActionMode mode) {

    }
}

}


1

Для смартфона с буфером обмена можно предотвратить подобное.

editText.setFilters(new InputFilter[]{new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            if (source.length() > 1) {
                return "";
            }  return null;
        }
    }});


0

Я обнаружил, что когда вы создаете фильтр ввода, чтобы избежать ввода нежелательных символов, вставка таких символов в текст редактирования не имеет никакого эффекта. Так что это тоже решает мою проблему.



0

Решение, которое сработало для меня, заключалось в создании настраиваемого Edittext и переопределении следующего метода:

public class MyEditText extends EditText {

private int mPreviousCursorPosition;

@Override
protected void onSelectionChanged(int selStart, int selEnd) {
    CharSequence text = getText();
    if (text != null) {
        if (selStart != selEnd) {
            setSelection(mPreviousCursorPosition, mPreviousCursorPosition);
            return;
        }
    }
    mPreviousCursorPosition = selStart;
    super.onSelectionChanged(selStart, selEnd);
}

}


0

Попробуй использовать.

myEditext.setCursorVisible(false);

       myEditext.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

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

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

        }

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

        public boolean onActionItemClicked(ActionMode mode,
                MenuItem item) {
            // TODO Auto-generated method stub
            return false;
        }
    });

0

Кто ищет решение в Kotlin, используйте приведенный ниже класс в качестве настраиваемого виджета и используйте его в xml.

class SecureEditText: TextInputEditText {

/** This is a replacement method for the base TextView class' method of the same name. This method
 * is used in hidden class android.widget.Editor to determine whether the PASTE/REPLACE popup
 * appears when triggered from the text insertion handle. Returning false forces this window
 * to never appear.
 * @return false
 */
override fun isSuggestionsEnabled(): Boolean {
    return false
}

override fun getSelectionStart(): Int {
    for (element in Thread.currentThread().stackTrace) {
        if (element.methodName == "canPaste") {
            return -1
        }
    }
    return super.getSelectionStart()
}

public override fun onSelectionChanged(start: Int, end: Int) {

    val text = text
    if (text != null) {
        if (start != text.length || end != text.length) {
            setSelection(text.length, text.length)
            return
        }
    }

    super.onSelectionChanged(start, end)
}

companion object {
    private val EDITTEXT_ATTRIBUTE_COPY_AND_PASTE = "isCopyPasteDisabled"
    private val PACKAGE_NAME = "http://schemas.android.com/apk/res-auto"
}

constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
    disableCopyAndPaste(context, attrs)
}

/**
 * Disable Copy and Paste functionality on EditText
 *
 * @param context Context object
 * @param attrs   AttributeSet Object
 */
private fun disableCopyAndPaste(context: Context, attrs: AttributeSet) {
    val isDisableCopyAndPaste = attrs.getAttributeBooleanValue(
        PACKAGE_NAME,
        EDITTEXT_ATTRIBUTE_COPY_AND_PASTE, true
    )
    if (isDisableCopyAndPaste && !isInEditMode()) {
        val inputMethodManager =
            context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        this.setLongClickable(false)
        this.setOnTouchListener(BlockContextMenuTouchListener(inputMethodManager))
    }
}

/**
 * Perform Focus Enabling Task to the widget with the help of handler object
 * with some delay
 * @param inputMethodManager is used to show the key board
 */
private fun performHandlerAction(inputMethodManager: InputMethodManager) {
    val postDelayedIntervalTime: Long = 25
    Handler().postDelayed(Runnable {
        this@SecureEditText.setSelected(true)
        this@SecureEditText.requestFocusFromTouch()
        inputMethodManager.showSoftInput(
            this@SecureEditText,
            InputMethodManager.RESULT_SHOWN
        )
    }, postDelayedIntervalTime)
}

/**
 * Class to Block Context Menu on double Tap
 * A custom TouchListener is being implemented which will clear out the focus
 * and gain the focus for the EditText, in few milliseconds so the selection
 * will be cleared and hence the copy paste option wil not pop up.
 * the respective EditText should be set with this listener
 *
 * @param inputMethodManager is used to show the key board
 */
private inner class BlockContextMenuTouchListener internal constructor(private val inputMethodManager: InputMethodManager) :
    View.OnTouchListener {
    private var lastTapTime: Long = 0
    val TIME_INTERVAL_BETWEEN_DOUBLE_TAP = 30
    override fun onTouch(v: View, event: MotionEvent): Boolean {
        if (event.getAction() === MotionEvent.ACTION_DOWN) {
            val currentTapTime = System.currentTimeMillis()
            if (lastTapTime != 0L && currentTapTime - lastTapTime < TIME_INTERVAL_BETWEEN_DOUBLE_TAP) {
                this@SecureEditText.setSelected(false)
                performHandlerAction(inputMethodManager)
                return true
            } else {
                if (lastTapTime == 0L) {
                    lastTapTime = currentTapTime
                } else {
                    lastTapTime = 0
                }
                performHandlerAction(inputMethodManager)
                return true
            }
        } else if (event.getAction() === MotionEvent.ACTION_MOVE) {
            this@SecureEditText.setSelected(false)
            performHandlerAction(inputMethodManager)
        }
        return false
    }
}

}


0

Я добавил функцию расширения на языке Kotlin :

fun EditText.disableTextSelection() {
    this.setCustomSelectionActionModeCallback(object : android.view.ActionMode.Callback {
        override fun onActionItemClicked(mode: android.view.ActionMode?, item: MenuItem?): Boolean {
            return false
        }
        override fun onCreateActionMode(mode: android.view.ActionMode?, menu: Menu?): Boolean {
            return false
        }
        override fun onPrepareActionMode(mode: android.view.ActionMode?, menu: Menu?): Boolean {
            return false
        }
        override fun onDestroyActionMode(mode: android.view.ActionMode?) {
        }
    })
}

вы можете использовать это так:

edit_text.disableTextSelection()

также добавил строку ниже в ваш xml:

                android:longClickable="false"
                android:textIsSelectable="false"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.