Android intercept paste\copy\cut on editText
Solution 1
Seems there isn't much you can do by using the API: android paste event
I dug into the Android Source of the TextView
(EditText
is a TextView
with some different configuration) and found out that the menu used to offer the cut/copy/paste options is just a modified ContextMenu
(source).
As for a normal context-menu, the View must create the menu (source) and then handle the interaction in a callback-method (source).
Because the handling method is public
, we can simply hook into it by extending EditText
and overwriting the method to react on the different actions. Here is an example-implementation:
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();
}
}
Now, when the user uses cut/copy/paste, a Toast
is shown (of course you could do other things, too).
The neat thing is that this works down to Android 1.5 and you don't need to re-create the context-menu (like suggested in the above linked question), which will keep the constant look of the platform (for example with HTC Sense).
Solution 2
There is a much simpler way, although not 100% reliable.
Add TextChangedListener to your editbox:
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) {
}
});
If the text changes for more than 2 characters, you can assume it was pasted (some smileys take up two characters).
Of course it will not detect pasting when the user pastes 1 or 2 characters, and it will falsely report pasting if the change in text was triggered by something else.
But for most purposes, it gets the job done 👍
and_dev
Updated on July 09, 2022Comments
-
and_dev almost 2 years
How can I intercept this kind of events ?
I need to add some logic when the user trying to paste some text into my
EditText
i know i can useTextWatcher
but this entrypoint not good for me becuase i only need to intercept in case of paste and not every time the user press myEditText
, -
Nirav Mehta almost 10 yearsi got can't instantiate class no empty constructor error what solution of it ???
-
Lukas Knuth almost 10 yearswell, the class has no empty constructor. you have to pass it an instance of
Context
(if your code is in an Activity, you can pass itthis
). -
GuillermoMP over 8 yearsExpanded your solution with a listener so it can be used as a plug&play component. The gist gist.github.com/guillermomuntaner/82491cbf0c88dec560a5
-
Zxcv over 7 yearsHow to get the inserted Spanned String from the paste ?
-
Lukas Knuth over 7 years@Pierre you could add a
TextWatcher
and record the changes. If a change occurs and you get a fitting cut/paste/copy action, you can figure out which part of the content changed. -
Zxcv over 7 yearsFinally found out a better solution. I do not want a TextWatcher triggered each time a letter is pressed. So, I used the ClipBoardManager to override the pasted content. Thanks to: stackoverflow.com/questions/6651184/… and developer.android.com/guide/topics/text/copy-paste.html
-
tiagocarvalho92 almost 5 yearsThis doesn't work if your edittext is limited to 1 char only and you want to copy to multiple edittexts ( like a code with 1 et for each digit)
-
lenooh almost 5 yearstiagocarvalho92: yes, that is written in the description.
-
milosmns about 4 yearsThis seems ok. For I'd look into integrating with the system and maybe use auto-fill or that OTP provider thing that automatically reads the messages. It's a much better user experience. Also having a 'paste' button would do the trick. There's really no reason to be constrained to EditText in that scenario.