Jak wyłączyć kopiowanie / wklejanie z / do EditText

133

W mojej aplikacji jest ekran rejestracji, na którym nie chcę, aby użytkownik mógł kopiować / wklejać tekst do EditTextpola. Mam ustawić onLongClickListenerna każdym EditTexttak, że menu kontekstowe wykazujące kopiuj / wklej / inputMethod i inne opcje nie pojawi się. Dlatego użytkownik nie będzie mógł kopiować / wklejać do pól edycji.

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

Ale problem pojawia się, jeśli użytkownik włączył klawiaturę innej firmy niż domyślna dla Androida, która może mieć przycisk do kopiowania / wklejania lub może wyświetlać to samo menu kontekstowe. Jak więc wyłączyć kopiowanie / wklejanie w tym scenariuszu?

Daj mi znać, jeśli istnieją inne sposoby kopiowania / wklejania. (i być może jak je wyłączyć)

Każda pomoc będzie mile widziana.

rDroid
źródło
Jeśli operacja „wklej” pochodzi z edytora IME, nie ma standardowego sposobu na odróżnienie jej od zwykłych naciśnięć klawiszy. Jednym z pomysłów do wypróbowania jest zmierzenie czasu między pojawieniem się każdego znaku, a jeśli czas jest zbyt krótki, znaki pochodzą z operacji „wklejania”.
BitBank
wydaje się być brudnym rozwiązaniem! warte obejrzenia.
rDroid
1
użyj androida: longClickable = "false"
Azay Gupta

Odpowiedzi:

114

Jeśli używasz interfejsu API na poziomie 11 lub wyższym, możesz zatrzymać wyświetlanie kopiowania, wklejania, wycinania i niestandardowych menu kontekstowych przez.

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

Zwrócenie wartości false z onCreateActionMode (ActionMode, Menu) uniemożliwi uruchomienie trybu akcji (akcje Wybierz wszystko, Wytnij, Kopiuj i Wklej).

Zain Ali
źródło
1
a co z poziomem api poniżej 13?
Jonathan,
1
Nie rozumiem ani komentarzy, ta próbka działa api11 +, przed api11 nie było kopiowania i wklejania IIRC
scottyab
30
Nie działa dla mnie Przycisk Wklej pojawi się w przypadku dotknięcia niebieskiego wskaźnika kursora.
nieważne
8
Dla mnie też nie działa. Po dwukrotnym dotknięciu pojawia się menu kopiowania i wklejania.
Android Killer,
to już nie działa na
Androidzie
136

Najlepszą metodą jest użycie:

etUsername.setLongClickable(false);
Vicky Kapadia
źródło
60
Lub po prostu w xml android:longClickable="false":)
łomża
20
Przycisk Wklej pojawi się w przypadku dotknięcia niebieskiego wskaźnika kursora.
nieważne
17
Z pewnością zapobiegnie to długiemu klikaniu widoku, ale kontrolki edycji można również zażądać, dwukrotnie dotykając tekstu, co oznacza, że ​​to rozwiązanie nie jest kompletne. Miej to na uwadze dla swoich celów.
Kevin Grant
1
Ponadto skróty klawiaturowe mogą nadal działać (Ctrl + C) z klawiaturami zewnętrznymi.
Oleg Vaskevich
To nie działa w przypadku Ice Cream Sandwich, ponieważ opcje schowka można otworzyć przez podwójne dotknięcie tekstu, a także długie dotknięcie.
Paul Wintz
46

Możesz to zrobić, wyłączając długie naciśnięcie EditText

Aby to zaimplementować, po prostu dodaj następujący wiersz w xml -

android:longClickable="false"
Ameya Pandilwar
źródło
6
Problem polegał na tym, że użytkownik mojej aplikacji ma klawiaturę innej firmy, która ma przycisk kopiowania i wklejania.
rDroid
3
innym problemem jest to, że możesz zaznaczyć tekst podwójnym dotknięciem i ponownie pokazuje kopiuj / wklej
Nikola
37

Jestem w stanie wyłączyć funkcję kopiowania i wklejania w następujący sposób:

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);

Mam nadzieję, że to zadziała ;-)

Joseph Johnson
źródło
To jest dokładnie to samo rozwiązanie, które znalazłem na podstawie innych odpowiedzi powyżej. To powinno być oznaczone jako prawidłowe rozwiązanie, ponieważ obsługuje przypadki brzegowe inni nie
Andrew Hoefling
2
Ta opcja blokuje kopiowanie, ale nadal można wklejać, klikając kursor.
Mehul Kanzariya
13

Rozwiązanie Kotlin:

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

Następnie możesz po prostu wywołać tę metodę na swoim TextView:

override fun onCreate() {
    priceEditText.disableCopyPaste()
}
Alexandr
źródło
1
Cześć, używam tego podejścia, ale otrzymuję Type mismatchbłąd z tym opisem Required:ActionMode.Callback! Found: w tej części object: ActionMode.Callback. Masz jakiś pomysł, dlaczego to może nie działać?
Abdul Mateen
12

tutaj jest najlepszy sposób na wyłączenie kopiowania wycinania wklejania pracy editText we wszystkich wersjach

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;
            }
        });
    }
Hardik
źródło
To zadziałało dla mnie, po prostu musiałem dodać @TargetApi (Build.VERSION_CODES.HONEYCOMB)
Sheepdogsheep
11

Oprócz setCustomSelectionActionModeCallback i wyłączonych rozwiązań z długim kliknięciem , konieczne jest zapobieganie pojawianiu się menu WKLEJ / ZAMIEŃ po kliknięciu uchwytu zaznaczenia tekstu, jak na poniższym obrazku:

Uchwyt zaznaczania tekstu z menu wklejania

Rozwiązaniem jest zapobieganie pojawianiu się menu WKLEJ / ZASTĄP w show()metodzie (nieudokumentowanej) android.widget.Editorklasy. Zanim pojawi się menu, należy sprawdzić if (!canPaste && !canSuggest) return;. Dwie metody używane jako podstawa do ustawiania tych zmiennych znajdują się w EditTextklasie:

Bardziej kompletna odpowiedź brzmi dostępna tutaj .

CJBS
źródło
To jest PRAWIDŁOWE i KOMPLETNE rozwiązanie
FireZenk
W niektórych urządzeniach zamiast opcji Wklej schowek jest widoczna, działa tylko jako wklej. Sprawdziłem linki, ale mogę zapobiec wklejaniu, ale nie schowkowi. dowolny pomysł ?
Richa
5

Jeśli nie chcesz wyłączać długiego kliknięcia, ponieważ musisz wykonać jakąś funkcję przy długim kliknięciu, lepszym rozwiązaniem jest zwrócenie wartości true.

Twoje długie kliknięcie edittext będzie takie.

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

Zgodnie z dokumentacją Zwrócenie wartości „True” będzie oznaczać, że długie kliknięcie zostało obsłużone, więc nie ma potrzeby wykonywania domyślnych operacji.

Przetestowałem to na poziomie API 16, 22 i 25. Dla mnie działa dobrze. Mam nadzieję, że to pomoże.

muak
źródło
1
Dobry. Alternatywnie, po prostu ustaw android:longClickable="false"w XML
Alex Semeniuk
4

Przetestowałem to rozwiązanie i działa

    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;
      }
    });
Aakash Anuj
źródło
Użyłem tego kodu, aby zapobiec ze schowka, opcji kopiowania.Dziękuję
Deepak Borade
3

https://github.com/neopixl/PixlUI udostępnia EditTextmetodę

myEditText.disableCopyAndPaste().

I to działa na starym API

odemolliens
źródło
1
Robi to dokładnie to samo, co pół-rozwiązanie dostarczane przez stackoverflow.com/a/22756538/3063884 . Zobacz kod: github.com/neopixl/PixlUI/blob/master/Library/src/com/neopixl/ ... To podejście nadal nie zapobiega wyświetlaniu przez moduł obsługi zaznaczania tekstu „WKLEJ”, jeśli w schowku znajduje się tekst .
CJBS
3

Oto sposób na wyłączenie wyskakującego okienka „wklej”. Musisz nadpisać EditTextmetodę:

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

Podobnie można zrobić w przypadku innych działań.

Anton Tananaev
źródło
czy możesz powiedzieć wyłączenie schowka
Richa
2

Dodałem funkcję rozszerzenia w języku 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?) {
        }
    })
}

możesz tego użyć w ten sposób:

edit_text.disableTextSelection()

dodano również poniższy wiersz w Twoim xml:

                android:longClickable="false"
                android:textIsSelectable="false"
Adnan Abdollah Zaki
źródło
1

Przeczytaj Schowek, porównaj z danymi wejściowymi i godziną „wpisania” danych wejściowych. Jeśli schowek zawiera ten sam tekst i jest on zbyt szybki, usuń wklejone dane wejściowe.

kadir
źródło
1

@Zain Ali, twoja odpowiedź działa na API 11. Chciałem tylko zasugerować sposób, aby zrobić to również w API 10. Ponieważ musiałem utrzymywać mój projekt API w tej wersji, ciągle bawiłem się funkcjami dostępnymi w 2.3.3 i miałem możliwość to zrobić. Udostępniam poniższy fragment. Przetestowałem kod i zadziałał. Zrobiłem ten fragment w trybie pilnym. Zapraszam do ulepszania kodu, jeśli są jakieś zmiany, które można wprowadzić.

// 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;
    }
Aravind
źródło
1

rozwiązanie jest bardzo proste

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

        }
    });
   }
}

--------> podgląd <---------

Muhammad Ali
źródło
1

Spróbuj podążać za klasą niestandardową dla wcześniejszego kopiowania i wklejania 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) {

    }
}

}

Sagar Jethva
źródło
1

W przypadku smartfona ze schowkiem można temu zapobiec.

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;
        }
    }});
José Torres
źródło
0

Odkryłem, że kiedy tworzysz filtr wejściowy, aby uniknąć wprowadzania niechcianych znaków, wklejanie takich znaków do tekstu edycji nie przynosi żadnego efektu. Więc to również rozwiązuje mój problem.

rDroid
źródło
0

Możesz spróbować android: focusableInTouchMode = "false".

stdout
źródło
To nigdy nie
zadziała
0

Rozwiązaniem, które zadziałało, było utworzenie niestandardowego Edittext i zastąpienie następującej metody:

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

}

Palejandro
źródło
0

Spróbuj użyć.

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;
        }
    });
Thambidurai
źródło
0

Kto szuka rozwiązania w Kotlinie, użyj poniższej klasy jako niestandardowego widgetu i użyj go w 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
    }
}

}

Dev
źródło