介紹
Android提供了一個強大的基于剪貼板的復制和粘貼框架。它既支持簡單的數據類型,也支持復雜的數據類型,包括文本字符串、復雜的數據結構、文本和二進制流數據,甚至還支持應用程序資源。
如下圖所示:
由上圖可以簡單的得到Android剪切板模版主要由四個類構成:ClipboardManager
、ClipData
、ClipData.Item
、ClipDescription
.
簡單的描述:系統復制數據,就是創建一個
ClipData
對象放在ClipboardManager
全局上.ClipData
可以包括多條Item
子數據,子數據中復制內容可以是text
,url
,intent
,但是都是這些子數據都是來自一次復制,每次復制會覆蓋之前的復制內容.同時,ClipData
中包含一個ClipDescription
,用于描述本次復制內容的MimeType.
核心類
ClipboardManager
系統服務全局的剪切板類.如何得到如下:
ClipboardManager mClipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
定義當剪貼板上的主剪輯發生更改時調用的偵聽器回調:OnPrimaryClipChangedListener
.
// 添加剪貼板數據改變監聽器
mClipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
@Override
public void onPrimaryClipChanged() {
// 剪貼板中的數據被改變,此方法將被回調
System.out.println("onPrimaryClipChanged()");
}
});
// 移除指定的剪貼板數據改變監聽器
mClipboardManager.removePrimaryClipChangedListener(listener);
-
ClipData.Item
剪切板子數據類,它包含了text
、html
、Uri
或者Intent
數據,一個clip
對象可以包含一個或多個Item
對象。
一起來看看它的屬性:
final CharSequence mText;
final String mHtmlText;
final Intent mIntent;
Uri mUri;
就是一個數據類.
-
ClipDescription
剪切板的描述類.包含了ClipData
對象的metadata
信息,一般情況mimeType
只有一個.
一起看看它的屬性就知道干什么的類了.
public class ClipDescription implements Parcelable {
//默認的MimeTYpe
public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
public static final String MIMETYPE_TEXT_HTML = "text/html";
public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";
public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
public static final String EXTRA_TARGET_COMPONENT_NAME =
"android.content.extra.TARGET_COMPONENT_NAME";
public static final String EXTRA_USER_SERIAL_NUMBER = "android.content.extra.USER_SERIAL_NUMBER";
//包含一個標簽
final CharSequence mLabel;
//mimeType數組
final String[] mMimeTypes;
//可以保存額外的數據
private PersistableBundle mExtras;
......
}
一般使用前面四種:text、html、uri、intent.其中url比較特殊.如果使用Android
資源MimeType
需要由ContentResolver
提供.
什么是uri:
通用資源標志符(Universal Resource Identifier, 簡稱"URI")。
Uri代表要操作的數據,Android上可用的每種資源 - 圖像、視頻片段等都可以用Uri來表示。
Android的Uri由以下三部分組成: "content://"、數據的路徑、標示ID(可選)
-
ClipData
剪切對象,在有且僅有一個剪切板對象在系統服務中.言外之意,每一次復制前一次復制內容都會消失.
一起來看看它的屬性:
public class ClipData implements Parcelable {
//默認mimetype。 text/plain
static final String[] MIMETYPES_TEXT_PLAIN = new String[] {
ClipDescription.MIMETYPE_TEXT_PLAIN };
//text/html
static final String[] MIMETYPES_TEXT_HTML = new String[] {
ClipDescription.MIMETYPE_TEXT_HTML };
//urllist
static final String[] MIMETYPES_TEXT_URILIST = new String[] {
ClipDescription.MIMETYPE_TEXT_URILIST };
//intent
static final String[] MIMETYPES_TEXT_INTENT = new String[] {
ClipDescription.MIMETYPE_TEXT_INTENT };
//剪切板描述類
final ClipDescription mClipDescription;
final Bitmap mIcon;
//用于存放剪切板子數據
final ArrayList<Item> mItems;
.......
}
創建方式:
/**
* Create a new ClipData holding data of the type
* {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
*
* @param label User-visible label for the clip data.
* @param text The actual text in the clip.
* @return Returns a new ClipData containing the specified data.
*/
static public ClipData newPlainText(CharSequence label, CharSequence text) {
Item item = new Item(text);
return new ClipData(label, MIMETYPES_TEXT_PLAIN, item);
}
/**
* Create a new ClipData holding data of the type
* {@link ClipDescription#MIMETYPE_TEXT_HTML}.
*
* @param label User-visible label for the clip data.
* @param text The text of clip as plain text, for receivers that don't
* handle HTML. This is required.
* @param htmlText The actual HTML text in the clip.
* @return Returns a new ClipData containing the specified data.
*/
static public ClipData newHtmlText(CharSequence label, CharSequence text,
String htmlText) {
Item item = new Item(text, htmlText);
return new ClipData(label, MIMETYPES_TEXT_HTML, item);
}
/**
* Create a new ClipData holding an Intent with MIME type
* {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
*
* @param label User-visible label for the clip data.
* @param intent The actual Intent in the clip.
* @return Returns a new ClipData containing the specified data.
*/
static public ClipData newIntent(CharSequence label, Intent intent) {
Item item = new Item(intent);
return new ClipData(label, MIMETYPES_TEXT_INTENT, item);
}
/**
* Create a new ClipData holding a URI. If the URI is a content: URI,
* this will query the content provider for the MIME type of its data and
* use that as the MIME type. Otherwise, it will use the MIME type
* {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
*
* @param resolver ContentResolver used to get information about the URI.
* @param label User-visible label for the clip data.
* @param uri The URI in the clip.
* @return Returns a new ClipData containing the specified data.
*/
static public ClipData newUri(ContentResolver resolver, CharSequence label,
Uri uri) {
//創建item
Item item = new Item(uri);
/*獲取mimeType*/
String[] mimeTypes = null;
if ("content".equals(uri.getScheme())) {
String realType = resolver.getType(uri);
mimeTypes = resolver.getStreamTypes(uri, "*/*");
if (realType != null) {
if (mimeTypes == null) {
mimeTypes = new String[] { realType };
} else {
String[] tmp = new String[mimeTypes.length + 1];
tmp[0] = realType;
System.arraycopy(mimeTypes, 0, tmp, 1, mimeTypes.length);
mimeTypes = tmp;
}
}
}
if (mimeTypes == null) {
mimeTypes = MIMETYPES_TEXT_URILIST;
}
return new ClipData(label, mimeTypes, item);
}
/**
* Create a new ClipData holding an URI with MIME type
* {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
* Unlike {@link #newUri(ContentResolver, CharSequence, Uri)}, nothing
* is inferred about the URI -- if it is a content: URI holding a bitmap,
* the reported type will still be uri-list. Use this with care!
*
* @param label User-visible label for the clip data.
* @param uri The URI in the clip.
* @return Returns a new ClipData containing the specified data.
*/
static public ClipData newRawUri(CharSequence label, Uri uri) {
//創建item
Item item = new Item(uri);
return new ClipData(label, MIMETYPES_TEXT_URILIST, item);
}
clipData
對象創建后塞入Clipboardmanager
即可:
//Clipboardmanager方法
/**
* Sets the current primary clip on the clipboard. This is the clip that
* is involved in normal cut and paste operations.
*
* @param clip The clipped data item to set.
*/
public void setPrimaryClip(ClipData clip) {
try {
if (clip != null) {
clip.prepareToLeaveProcess(true);
}
getService().setPrimaryClip(clip, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- 轉換成字符串
//任何作為HTML格式返回的文本都將作為具有樣式跨度的文本返回。
CharSequence coerceToStyledText(Context context);
//如果getText()是非空的,則返回該值。
//如果getUri()非null,則嘗試從其內容提供程序檢索其數據作為文本流。如果成功,將文本復制到字符串中并返回。如果它不是內容:URI或內容提供程序不提供文本表示,則將原始URI作為字符串返回。
//如果getIntent()非null,則將其轉換為intent: URI并返回。
//否則,返回一個空字符串。
CharSequence coerceToText(Context context) ;
//如果getHtmlText()非null,則返回該值。
//如果getText()是非空的,返回它,轉換為有效的HTML文本。如果此文本包含樣式跨度,則使用HTML . tohtml (span)將其轉換為HTML格式。
//如果getUri()非null,則嘗試從其內容提供程序檢索其數據作為文本流。
//如果提供程序可以提供文本/html數據,則首選該數據并按原樣返回。否則,將返回任何文本/*數據并轉義到HTML。
//如果它不是內容:URI或內容提供程序不提供文本表示,將返回包含到URI鏈接的HTML文本。
//如果getIntent()非null,則將其轉換為intent: URI并以HTML鏈接的形式返回。
//否則,返回一個空字符串。
String coerceToHtmlText(Context context)
詳細的內容可以查看官網,地址我也寫出來了,在最下面,哈哈哈.
- 注意
1、剪切板只會保存最近一次復制的內容.
2、MimeType
一般只有一個.(可以有多個)
3、系統全局的剪切板,其他應用也可以使用.
工具類
package com.rnx.react.modules.clip;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import java.util.List;
/**
* @Auther: weiwei.zhang06
* @Date: 2018/12/5 18:59
*/
public class ClipboardHelper {
public static final String TAG = ClipboardHelper.class.getSimpleName();
private Context mContext;
private volatile static ClipboardHelper mInstance;
private ClipboardManager mClipboardManager;
private ClipboardHelper(Context context) {
mContext = context;
mClipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
}
/**
* 獲取ClipboardUtil實例,記得初始化
*
* @return 單例
*/
public static ClipboardHelper getInstance(Context context) {
if (mInstance == null) {
synchronized (ClipboardHelper.class) {
if (mInstance == null) {
mInstance = new ClipboardHelper(context.getApplicationContext());
}
}
}
return mInstance;
}
/**
* 判斷剪貼板內是否有數據
*
* @return
*/
public boolean hasPrimaryClip() {
return mClipboardManager.hasPrimaryClip();
}
/**
* 獲取剪貼板中第一條String
*
* @return
*/
public String getClipText() {
if (!hasPrimaryClip()) {
return null;
}
ClipData data = mClipboardManager.getPrimaryClip();
if (data != null
&& mClipboardManager.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
return data.getItemAt(0).getText().toString();
}
return null;
}
/**
* 獲取剪貼板中第一條String
*
* @param context
* @return
*/
public String getClipText(Context context) {
return getClipText(context, 0);
}
/**
* 獲取剪貼板中指定位置item的string
*
* @param context
* @param index
* @return
*/
public String getClipText(Context context, int index) {
if (!hasPrimaryClip()) {
return null;
}
ClipData data = mClipboardManager.getPrimaryClip();
if (data == null) {
return null;
}
if (data.getItemCount() > index) {
return data.getItemAt(index).coerceToText(context).toString();
}
return null;
}
/**
* 將文本拷貝至剪貼板
*
* @param text
*/
public void copyText(String label, String text) {
ClipData clip = ClipData.newPlainText(label, text);
mClipboardManager.setPrimaryClip(clip);
}
/**
* 將HTML等富文本拷貝至剪貼板
*
* @param label
* @param text
* @param htmlText
*/
public void copyHtmlText(String label, String text, String htmlText) {
ClipData clip = ClipData.newHtmlText(label, text, htmlText);
mClipboardManager.setPrimaryClip(clip);
}
/**
* 將Intent拷貝至剪貼板
*
* @param label
* @param intent
*/
public void copyIntent(String label, Intent intent) {
ClipData clip = ClipData.newIntent(label, intent);
mClipboardManager.setPrimaryClip(clip);
}
/**
* 將Uri拷貝至剪貼板
* If the URI is a content: URI,
* this will query the content provider for the MIME type of its data and
* use that as the MIME type. Otherwise, it will use the MIME type
* {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
* 如 uri = "content://contacts/people",那么返回的MIME type將變成"vnd.android.cursor.dir/person"
*
* @param cr ContentResolver used to get information about the URI.
* @param label User-visible label for the clip data.
* @param uri The URI in the clip.
*/
public void copyUri(ContentResolver cr, String label, Uri uri) {
ClipData clip = ClipData.newUri(cr, label, uri);
mClipboardManager.setPrimaryClip(clip);
}
/**
* 將多組數據放入剪貼板中,如選中ListView多個Item,并將Item的數據一起放入剪貼板
*
* @param label User-visible label for the clip data.
* @param mimeType mimeType is one of them:{@link ClipDescription#MIMETYPE_TEXT_PLAIN},
* {@link ClipDescription#MIMETYPE_TEXT_HTML},
* {@link ClipDescription#MIMETYPE_TEXT_URILIST},
* {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
* @param items 放入剪貼板中的數據
*/
public void copyMultiple(String label, String mimeType, List<ClipData.Item> items) {
if (items == null || items.size() == 0) {
throw new IllegalArgumentException("argument: items error");
}
int size = items.size();
ClipData clip = new ClipData(label, new String[]{mimeType}, items.get(0));
for (int i = 1; i < size; i++) {
clip.addItem(items.get(i));
}
mClipboardManager.setPrimaryClip(clip);
}
public void copyMultiple(String label, String[] mimeTypes, List<ClipData.Item> items) {
if (items == null || items.size() == 0) {
throw new IllegalArgumentException("argument: items error");
}
int size = items.size();
ClipData clip = new ClipData(label, mimeTypes, items.get(0));
for (int i = 1; i < size; i++) {
clip.addItem(items.get(i));
}
mClipboardManager.setPrimaryClip(clip);
}
public CharSequence coercePrimaryClipToText() {
if (!hasPrimaryClip()) {
return null;
}
return mClipboardManager.getPrimaryClip().getItemAt(0).coerceToText(mContext);
}
public CharSequence coercePrimaryClipToStyledText() {
if (!hasPrimaryClip()) {
return null;
}
return mClipboardManager.getPrimaryClip().getItemAt(0).coerceToStyledText(mContext);
}
public CharSequence coercePrimaryClipToHtmlText() {
if (!hasPrimaryClip()) {
return null;
}
return mClipboardManager.getPrimaryClip().getItemAt(0).coerceToHtmlText(mContext);
}
/**
* 獲取當前剪貼板內容的MimeType
*
* @return 當前剪貼板內容的MimeType
*/
public String getPrimaryClipMimeType() {
if (!hasPrimaryClip()) {
return null;
}
return mClipboardManager.getPrimaryClipDescription().getMimeType(0);
}
/**
* 獲取剪貼板內容的MimeType
*
* @param clip 剪貼板內容
* @return 剪貼板內容的MimeType
*/
public String getClipMimeType(ClipData clip) {
return clip.getDescription().getMimeType(0);
}
/**
* 獲取剪貼板內容的MimeType
*
* @param clipDescription 剪貼板內容描述
* @return 剪貼板內容的MimeType
*/
public String getClipMimeType(ClipDescription clipDescription) {
return clipDescription.getMimeType(0);
}
/**
* 清空剪貼板
*/
public void clearClip() {
mClipboardManager.setPrimaryClip(ClipData.newPlainText(null, ""));
}
public ClipData getClipData() {
if (!hasPrimaryClip()) {
return null;
}
return mClipboardManager.getPrimaryClip();
}
}
官網: https://developer.android.com/guide/topics/text/copy-paste#java
ClipboardManger api: https://developer.android.com/reference/android/content/ClipboardManager
ClipData api: https://developer.android.com/reference/android/content/ClipData
ClipData.item api: https://developer.android.com/reference/android/content/ClipData.Item
ClipDescription api: https://developer.android.com/reference/android/content/ClipDescription