Android使用ClipBoardManager提供对复制和粘贴功能的支持。 developer.android.com提供了简短的说明以及一张有助于理解“复制粘贴”框架的图像。

“要复制数据,应用程序将ClipData对象放在ClipboardManager全局剪贴板上。 ClipData包含一个或多个ClipData.Item对象和一个ClipDescription对象。 要粘贴数据,应用程序获取ClipData,从ClipDescription获取其MIME类型,并从ClipData.Item或ClipData.Item引用的内容提供程序获取数据。”

本教程介绍了JellyBean中引入的最新功能,支持样式文本。 我们将介绍下面列出的方法。 HTML支持的方法

  • ClipData.newHtmlText()与剪贴板
  • Intent.putExtra()与Intent.EXTRA_HTML_TEXT
  • Intent.setClipData()与newHtmlText()方法

项目信息:有关项目的元数据。 平台版本: Android API级别16。 IDE: Eclipse Helios服务版本2 模拟器: Android 4.1(API 16) 先决条件:对Android应用程序框架和Intent有初步了解。 示例源代码

首先,通过Eclipse> File> New Project> Android Application Project创建项目。 将出现以下对话框。 填写必填字段,即“应用程序名称”,“项目名称”和“包”。 现在按下一步按钮。

出现对话框后,选择BlankActivity,然后单击下一步 。

在下面显示的对话框中填写“活动名称”和“布局”文件名称,然后单击“ 完成”按钮。

此过程将设置基本项目文件。 现在,我们将在布局activity_jbclipboard.xml文件中添加视图组件。 您可以使用图形布局编辑器或xml编辑器来修改布局文件。 在此布局中,我们将添加四个按钮,分别是CopyHtml,pasteHtml,sendHtmlIntent和sendClipdataIntent按钮,分别是复制,粘贴,发送html Intent和发送clipdata目的并附加onClick方法。 这些方法将在JBClipboard类中定义。 我们还将包括两个单选按钮,即“粘贴HTML”和“粘贴文本”。 这些单选按钮有助于选择要从剪贴板提取的所需文本类型。 我们也有三个EditViews来显示文本。 第一个Editview包含样式文本,第二个显示HTML或文本字符串。 第三个显示了Coerce HTML字符串。 布局文件如下所示。

<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    xmlns:tools='http://schemas.android.com/tools'
    android:layout_width='match_parent'
    android:layout_height='match_parent' 
    android:orientation='vertical'>

    <EditText
        android:id='@+id/etCopy'
        android:layout_width='fill_parent'
        android:layout_height='wrap_content'
        android:padding='@dimen/padding_medium'
        android:gravity='top'   
        android:scrollHorizontally='false'
        android:inputType='textMultiLine'
         />
    <RadioGroup 
       android:id='@+id/rbgTextHTML'
       android:orientation='horizontal'
       android:layout_width='fill_parent'
       android:layout_height='wrap_content'
       >
         <RadioButton 
           android:id='@+id/rbHtml'
           android:layout_weight='.5'
           android:layout_width='0dp' 
           android:layout_height='wrap_content'
           android:checked='true'
           android:text='@string/rbHtml'/>
       <RadioButton
           android:id='@+id/rbText'
           android:layout_weight='.5'
           android:layout_width='0dp' 
           android:layout_height='wrap_content'
           android:text='@string/rbText'/>
     
   </RadioGroup>
    <LinearLayout 
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:orientation='horizontal'>
   <Button 
       android:layout_width='0dp'
       android:layout_height='wrap_content'
       android:layout_weight='.5'
       android:onClick='copyHtml'
       android:text='@string/btCopy'/>
   <Button 
       android:layout_width='0dp'
       android:layout_height='wrap_content'
       android:layout_weight='.5'
       android:onClick='pasteHtml'
       android:text='@string/btPaste'/>
   </LinearLayout>
   <LinearLayout android:layout_width='fill_parent'
       android:layout_height='wrap_content'
       android:orientation='horizontal'>
       <Button
           android:layout_width='0dp'
           android:layout_weight='.5'
           android:layout_height='wrap_content'
           android:onClick='sendHtmlIntent'
           android:text='@string/btSendHtmlIntent'/>
       <Button 
           android:layout_width='0dp'
           android:layout_weight='.5'
           android:layout_height='wrap_content'
           android:onClick='sendClipdataIntent'
           android:text='@string/btSendClipdataIntent'/>
   </LinearLayout>
   <TextView
       android:layout_width='fill_parent'
       android:layout_height='wrap_content'
       android:text='@string/tvCopiedText'/>
   <EditText
       android:id='@+id/etPaste' 
       android:layout_width='fill_parent'
       android:layout_height='wrap_content'
       android:inputType='textMultiLine'
        android:gravity='top'   
        android:scrollHorizontally='false'
       />
   <TextView
       android:layout_width='fill_parent'
       android:layout_height='wrap_content'
       android:text='@string/tvcoerceText'/>
   <EditText
       android:id='@+id/etPasteCoerceText' 
       android:layout_width='fill_parent'
       android:layout_height='wrap_content'
       android:gravity='top'   
       android:scrollHorizontally='false'
       android:inputType='textMultiLine'/>
</LinearLayout>

现在,我们需要为两个不同的活动添加另外两个布局文件。 让我们通过Eclipse> File> Android XML file定义第一个Layout 文件 。 最终,我们得到以下对话框。 确保选择了布局资源类型。 将布局文件命名为activity_htmlintent,然后单击Finish 。

添加两个用于显示文本标签的TextViews和两个用于显示HTML和文本字符串的EditTexts视图。 此布局文件将与HTMLIntentActivity.java附加在一起,一旦广播“ text / html”类型的意图,即会调用该布局文件。 下面给出了activity_htmlintent.xml的内容:

<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    android:layout_width='match_parent'
    android:layout_height='match_parent'
    android:orientation='vertical' >
    <TextView
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:text='@string/tvIntentHtml' />
    <EditText
        android:id='@+id/etHtml'
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:inputType='textMultiLine'
        android:padding='@dimen/padding_medium'
        android:scrollHorizontally='false' />
    <TextView
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:text='@string/tvIntentText' />
    <EditText
        android:id='@+id/etText'
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:inputType='textMultiLine'
        android:padding='@dimen/padding_medium'
        android:scrollHorizontally='false' />
</LinearLayout>

现在,我们将定义另一个名为activity_clipdataintent.xml的布局文件。 按照上面给出的类似步骤生成布局xml文件。 该文件与上面的文件相似,并且包含两个EditView和两个TextViewThe。 该文件的内容如下。 该布局文件将附加到ClipdataIntentActivity类,该类在传递带有Clipdata对象的Intent时被调用。

<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
    android:layout_width='match_parent'
    android:layout_height='match_parent'
    android:orientation='vertical' >

    <TextView
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:text='@string/tvIntentClipdataHtml' />

    <EditText
        android:id='@+id/etClipBoardHtml'
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:inputType='textMultiLine'
        android:padding='@dimen/padding_medium'
        android:scrollHorizontally='false' />

    <TextView
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:text='@string/tvIntentClipdataText' />

    <EditText
        android:id='@+id/etClipBoardText'
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:inputType='textMultiLine'
        android:padding='@dimen/padding_medium'
        android:scrollHorizontally='false' />
</LinearLayout>

您可能已经注意到,布局文件中已使用了字符串资源。 如下所示在string.xml中定义此字符串常量。

<resources>

    <string name='app_name'>JellyBeanClipboard</string>
    <string name='menu_settings'>Settings</string>
    <string name='title_activity_jbclipboard'>JBClipboard</string>
    <string name='title_activity_htmlintent'>Html Intent Activity</string>
    <string name='title_activity_clipdataintent'>ClipData Intent Activity</string> 
    <!-- CDATA tag is required otherwise you can't have the html text
       properly parsed in Textview  -->
   <string name='tvHtml'><![CDATA[<b>Link:</b> <a href='http://www.code4reference.com'>Code4Reference</a>]]></string>
   
   <!-- Text string for button -->
   <string name='btCopy'>Copy</string>
   <string name='btPaste'>Paste</string>
   <string name='btSendHtmlIntent'>send HTML Intent</string>
   <string name='btSendClipdataIntent'>send ClipData Intent</string>
   
   <!-- Text string for RadioButton -->
   <string name='rbHtml'>Paste Html</string>
   <string name='rbText'>Paste Text</string>
   
   <!-- Text string for Text View -->
   <string name='tvCopiedText'><b><i>Copied text</i></b></string>
   <string name='tvcoerceText'><b><i>Copied coerce Text</i></b></string>
    <string name='tvIntentText'><b><i>Intent Text</i></b></string>
   <string name='tvIntentHtml'><b><i>Intent Html</i></b></string>
   <string name='tvIntentClipdataText'><b><i>Intent Clipdata Text</i></b></string>
   <string name='tvIntentClipdataHtml'><b><i>Intent Clipdata Html</i></b></string>
</resources>

一旦完成了布局文件,就可以定义活动类了。 让我们定义称为JBClipboard的主要活动。 此活动有使用HTML支持的API的各种方法。 嵌入的注释将有助于理解代码。

package com.code4reference.rakesh.jellybeanclipboard;

import android.app.Activity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Html;
import android.text.Spannable;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;

import com.example.jellybeanclipboard.R;

public class JBClipboard extends Activity {

 EditText etCopy;
 EditText etPaste;
 EditText etPasteCoerceText;
 RadioButton rbText;
 RadioButton rbHtml;
 ClipboardManager mClipboard;

 ClipboardManager.OnPrimaryClipChangedListener mPrimaryChangeListener = new ClipboardManager.OnPrimaryClipChangedListener() {
  /**
   * This method is a callback. It get called when the primary clip 
   * on the clipboard changes. 
   */
  public void onPrimaryClipChanged() {
   //Toast message will appear whenever the clipboad 
   //primary data changes.
   Utility.showToastMessage(getApplicationContext(),
     'Primary clipdata changed', Toast.LENGTH_SHORT);
  }
 };

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_jbclipboard);
  etCopy = (EditText) findViewById(R.id.etCopy);
  etPaste = (EditText) findViewById(R.id.etPaste);
  etPasteCoerceText = (EditText) findViewById(R.id.etPasteCoerceText);
  etCopy.setText(Html.fromHtml(getString(R.string.tvHtml)));
  rbText = (RadioButton) findViewById(R.id.rbText);
  rbHtml = (RadioButton) findViewById(R.id.rbHtml);
  mClipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
  mClipboard.addPrimaryClipChangedListener(mPrimaryChangeListener);
 }

 /**
  * This method gets called when 'Copy' button get pressed.
  * @param view
  */
 public void copyHtml(View view) {
  String htmlText = getHtmltxt(etCopy);
  String plainText = getOnlyText(etCopy);
  mClipboard.setPrimaryClip(ClipData.newHtmlText('HTML Text', plainText,
    htmlText));

 }
 /**
  * This method gets called when 'Paste' button get pressed.
  * @param view
  */
 public void pasteHtml(View view) {
  // Check if there is primary clip exsiting.
  // If it does then echeck the mime type to make sure
  // it has HTML content.
  if (mClipboard.hasPrimaryClip()
    && mClipboard.getPrimaryClipDescription().hasMimeType(
      ClipDescription.MIMETYPE_TEXT_HTML)) {
   // Get the very first item from the clip.
   ClipData.Item item = mClipboard.getPrimaryClip().getItemAt(0);

   // If 'Paste HTML' radio button is selected then paste
   // HTML in the Textview.
   if (rbHtml.isChecked()) {
    etPaste.setText(item.getHtmlText());
   } else {
    // Paste the only text version.
    etPaste.setText(item.getText());
   }
   // Paste the CoerceText .
   etPasteCoerceText.setText(item.coerceToText(this));
  }
 }
 /**
  * This method gets called when 'send Html Intent' button get pressed.
  * @param view
  */
 public void sendHtmlIntent(View view) {
  // This kind of intent can be handle by this application
  // Or other application which handle text/html type Intent
  Intent intent = new Intent(Intent.ACTION_SEND);

  String htmlText = getHtmltxt(etCopy);
  String text = getOnlyText(etCopy);
  intent.putExtra(Intent.EXTRA_HTML_TEXT, htmlText);
  intent.putExtra(Intent.EXTRA_TEXT, text);
  intent.setType('text/html');
  startActivity(Intent.createChooser(intent, null));
 }

 /**
  * This method gets called when 'send Clipdata Intent' button get pressed.
  * 
  * @param view
  */
 public void sendClipdataIntent(View view) {
  String htmlText = getHtmltxt(etCopy);
  String plainText = getOnlyText(etCopy);
  Intent intent = new Intent(this, ClipdataIntentActivity.class);
                //create a clipdata object with HTML text.
                //and associate with the intent.
  intent.setClipData(ClipData.newHtmlText(
    'HTML text in Intent's clipdata', plainText, htmlText));
                //Start the activity which can handle clipData object.
  startActivity(intent);
 }
 @Override
    protected void onDestroy() {
        super.onDestroy();
        //Remove the ClipChanged Listener to save the resources.
        mClipboard.removePrimaryClipChangedListener(mPrimaryChangeListener);
    }
 /**
  * This method gets the EditText object and returns the HTML text. It
  * can be called only with EditTexts having spannable object with
  * the HTML text.
  * 
  * @param editText
  * @return
  */
 private String getHtmltxt(EditText editText) {
                //get the spannable object from EditText
  Spannable spannable = (Spannable) editText.getText();
                //return the HTML text from spannable object.
  return Html.toHtml(spannable);
 }

 /**
  * This method takes the EditText object which has spannable object with HTML
  * text and returns the simple text without HTML tags.
  * 
  * @param editText
  * @return
  */
 private String getOnlyText(EditText editText) {
  return editText.getText().toString();
 }
}

现在,我们将定义用于处理HTML文本意图的HTMLIntentActivity 。 预期意图将由主要活动(JBClibboard)触发

package com.code4reference.rakesh.jellybeanclipboard;

import com.example.jellybeanclipboard.R;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.EditText;

public class HtmlIntentActivity extends Activity {

 private EditText etHtml;
 private EditText etText;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_htmlintent);
  etHtml = (EditText) findViewById(R.id.etHtml);
  etText = (EditText) findViewById(R.id.etText);

  //Get the intent that started this activity
  Intent intent = getIntent();
                //Make sure intent and its type is not null.
  if (intent != null && intent.getType() != null
    && intent.getType().equals('text/html')) {
   //This contition will full-fill when this application receive the 
   //intent who's type is 'test/html'. In this application sendHtmlIntent
   //method sends this type of Intent. 
   Bundle bundle = intent.getExtras();
   if(bundle != null){
    etHtml.setText(bundle.getCharSequence(Intent.EXTRA_HTML_TEXT));
    etText.setText(bundle.getCharSequence(Intent.EXTRA_TEXT));
   }
  }
 }
}

现在,我们将定义另一个名为ClipdataIntentActivity的活动,该活动处理具有clilpdata对象的Intent。 ClipdataIntentActivity类的内容如下。

package com.code4reference.rakesh.jellybeanclipboard;

import android.app.Activity;
import android.content.ClipboardManager;
import android.content.Intent;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.Toast;
import android.content.ClipData;
import android.content.ClipDescription;

import com.example.jellybeanclipboard.R;

public class ClipdataIntentActivity extends Activity {
 private EditText etHtml;
 private EditText etText;
 ClipboardManager mClipboard;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_clipdataintent);
  etHtml = (EditText) findViewById(R.id.etClipBoardHtml);
  etText = (EditText) findViewById(R.id.etClipBoardText);

  //Get the intent that started this activity
  Intent intent = getIntent();
  if (intent != null) {
   ClipData clipdata = intent.getClipData();
                        //Make sure clipdata object is not null and it has HTML MIME type.
   if (clipdata != null
     && clipdata.getDescription().hasMimeType(
       ClipDescription.MIMETYPE_TEXT_HTML)) {

    ClipData.Item item = clipdata.getItemAt(0);
    etHtml.setText(item.getHtmlText());
    etText.setText(item.getText());
   } else {
    Utility.showToastMessage(this,
      'Intent clipdata doesn't have HTML', Toast.LENGTH_SHORT);
   }

  }
 }

}

创建另一个名为Utility的类。 它包含显示烤面包消息的方法。 您可能已经注意到此函数是静态的,因此无需创建对象来调用此方法。 将实用程序方法放在单独的文件中,然后在不同位置访问此文件始终是一个好主意。 这样,您的代码将井井有条。

package com.code4reference.rakesh.jellybeanclipboard;

import android.content.Context;
import android.widget.Toast;

public class Utility {

 public static void showToastMessage(Context context, String message, int duration){
  Toast.makeText(context, message, duration).show();
 }
}

最后定义Anroid Manifest文件,该文件主要向Android系统提供应用程序信息。 在这里,您应该注意到,HtmlIntentActivity活动具有一个意图过滤器,并且将意图类型指定为“ text / html”。 这基本上意味着该活动可以处理类型为text / html的意图。 文件的其余部分简单易懂。

<manifest xmlns:android='http://schemas.android.com/apk/res/android'
    package='com.example.jellybeanclipboard'
    android:versionCode='1'
    android:versionName='1.0' >

    <uses-sdk
        android:minSdkVersion='16'
        android:targetSdkVersion='16' />

    <application
        android:icon='@drawable/ic_launcher'
        android:label='@string/app_name'
        android:theme='@style/AppTheme' >
        <activity
            android:name='com.code4reference.rakesh.jellybeanclipboard.JBClipboard'
            android:label='@string/title_activity_jbclipboard' >
            <intent-filter>
                <action android:name='android.intent.action.MAIN' />
                <category android:name='android.intent.category.LAUNCHER' />
            </intent-filter>
        </activity>
        <activity android:name='com.code4reference.rakesh.jellybeanclipboard.ClipdataIntentActivity'
            android:label='@string/title_activity_clipdataintent' >
        </activity>
        <activity android:name='com.code4reference.rakesh.jellybeanclipboard.HtmlIntentActivity'
            android:label='@string/title_activity_htmlintent' >
            <intent-filter>
                <action android:name='android.intent.action.SEND' />
                <category android:name='android.intent.category.DEFAULT' />
                <!-- This activity will get launched when proper Intent type will match.
                In this case Intent type is 'text/html' -->
                <data android:mimeType='text/html' />
            </intent-filter>
        </activity>
    </application>

</manifest>

一旦完成编码,就执行它。 您可以在Android设备或模拟器上启动此应用程序。 确保Android版本为16(Jelly Bean)或更高版本,然后此应用程序才能运行。 应用程序的屏幕截图如下所示。

您可以在github上获取源代码。

祝您编程愉快,别忘了分享!

参考: 具有Intent的复制粘贴功能,并支持Android上HTML。 从我们的JCG合作伙伴 Rakesh Cusat在Code4Reference博客上获得。

翻译自: https://www.javacodegeeks.com/2012/09/android-copy-paste-with-intent-and.html