本文的剪切複製粘貼事件只針對文本,URI 和 intent 不在討論範圍內。
實例代碼實現了2個功能:
- 監聽剪切複製粘貼事件;
- 獲取剪切複製或粘貼的文本;
剪切複製
有2個方法監聽剪切複製事件:剪切板和 EditText 的 onTextContextMenuItem() 方法。
二者的主要區別是:
- 剪切板是系統層面的全局性質的監聽,而onTextContextMenuItem 只對某個 EditText 控件有效。
- 剪切板只能監聽到剪切複製事件,而無法監聽到粘貼事件,而 onTextContextMenuItem 能既能監聽到剪切複製事件,又能監聽粘貼事件;
方法一:剪切板
關於剪切板,詳見官方文檔:ClipboardManager。
在這裏囉嗦幾句關於 Clipboard 的知識點:
- 剪切板不僅可以存文本,還可以存 URI 和 Intent;
- 剪切板上只保持對 PrimaryClip 的引用,即最新一次的剪切數據;
- OnPrimaryClipChangedListener 回調只對剪切和複製操作有效,即只有剪切板數據增加時才調用 OnPrimaryClipChangedListener;
- 剪切板上有多個 ClipData 構成,每次剪切和複製事件都會產生一個 ClipData,ClipData 包含 ClipDescprition 和 若干個保存數據的 ClipData.Item;
監聽剪切和複製事件,如果是文本則保存對應文本:
private void registerClipEvents() {
final ClipboardManager manager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
manager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
@Override
public void onPrimaryClipChanged() {
if (manager.hasPrimaryClip() && manager.getPrimaryClip().getItemCount() > 0) {
CharSequence addedText = manager.getPrimaryClip().getItemAt(0).getText();
if (addedText != null) {
Log.d(TAG, "copied text: " + addedData);
}
}
}
});
}
注意,一定要在 onDestroy() 方法裏面去調用 addPrimaryClipChangedListener() 註銷掉,否則會出現內存泄露。
方法二:EditText#onTextContextMenuItem
在該方法中,我們可以監聽到剪切、複製和粘貼事件,但是需要繼承 EditText 重寫該方法:
public final class Listen2PasteEditText extends android.support.v7.widget.AppCompatEditText {
private static final String TAG = "Listen2PasteEditText";
private Context mContext;
public Listen2PasteEditText(Context context) {
super(context);
mContext = context;
}
public Listen2PasteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
@Override
public boolean onTextContextMenuItem(int id) {
switch (id) {
case android.R.id.cut:
if (mContext instanceof IClipCallback) {
((IClipCallback) mContext).onCut(null);
break;
case android.R.id.copy:
if (mContext instanceof IClipCallback) {
((IClipCallback) mContext).onCopy(null);
break;
case android.R.id.paste:
if (mContext instanceof IClipCallback) {
((IClipCallback) mContext).onPaste(null);
}
}
return super.onTextContextMenuItem(id);
}
}
其中,IClipCallback 是個接口, Listen2PasteEditText 所在的 Activity 需要實現該接口。
IClipCallback 聲明如下:
public interface IClipCallback {
void onCut(Object o);
void onCopy(Object o);
void onPaste(Object o);
}
注意,上述代碼只是讓我們監聽到了剪切和複製事件,要想獲取文本,還是要藉助剪切板,具體見 registerClipEvents() 方法,此處不再贅述。
粘貼
剪切板無法監聽到粘貼事件,只能通過 EditText#onTextContextMenuItem() 方法實現。
至於得到粘貼文本,還是需要通過剪切板獲得。
具體代碼見方法二。