Android自定义文本选中模式(全选、复制,剪切,粘帖)

为了方便操作,在PC端我们常用的Ctrl+A(全选)/Ctrl+C(复制)/Ctrl+X(剪切)/Ctrl+V(粘帖)提高了我们的办公效率。然后在手机端怎么实现呢?我花了一天的时间研究了一下。


  • 首先说一下TextView的选中,要想选中TextView中的文本有两种方式:
    1、setSelectAllOnFocus(true);
    2、android:textIsSelectable=”true”
  • 然后看一下EditText
    这里写图片描述
    从上面的图可以看出EditText是继承于TextView的,所以setSelectAllOnFocus(true)和android:textIsSelectable=”true”对它也同样适用,不过EditText默认setSelectAllOnFocus(true),所以没有必要手动设置;如果真的在布局文件中设置了android:textIsSelectable=”true”,那么EditText就不能被编辑,失去了光标,如下图:
    这里写图片描述
    所以android:textIsSelectable=”true”一般是给TextView设置的。

首先我们看一下默认的选中模式(上面弹出操作提示框):
这里写图片描述
那么要想改变原有的东西呢?这里有一个方法

setCustomSelectionActionModeCallback(new MyActionModeCallback(ActionMode.Callback callback));

通过ActionMode.Callback中的四个回调方法进行操作:

//创建菜单
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            return true;
        }
//这个相当于是菜单创建好以后的操作
        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            return true;
        }
//菜单中item的点击处理
        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
            return true;
        }
//菜单销毁操作
        @Override
        public void onDestroyActionMode(ActionMode actionMode) {

        }

首先要去自定义一个菜单布局:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item
        android:id="@+id/it_all"
        android:title="全选"
        android:icon="@drawable/all"
        />
    <item
        android:id="@+id/it_copy"
        android:title="复制"
        android:icon="@drawable/copy"
        />
    <item
        android:id="@+id/it_cut"
        android:title="剪切"
        android:icon="@drawable/cut"
        />
    <item
        android:id="@+id/it_paste"
        android:title="粘帖"
        />
</menu>

这里的android:icon=“@drawable/xxx”设置了,但是不显示。然后在onCreateActionMode方法中去初始化菜单;

 MenuInflater menuInflater = actionMode.getMenuInflater();
            menuInflater.inflate(R.menu.menu,menu);
            return true;

菜单创建好以后就是具体的操作了。


全选


Edittext有个selectAll()方法来实现全选;这个方法是Edittext独有的,所以TextView是没这个方法的。
这里写图片描述


复制、剪切


复制和剪切的原理一样,就是最后的处理稍有不同,所以我把他们放在了同一个方法中进行处理。

  /**
     *  统一处理复制和剪切的操作
     * @param mode 用来区别是复制还是剪切
     * @return
     */
    private String getSelectText(SelectMode mode) {
        //获取剪切班管理者
        ClipboardManager cbs = (ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE);
        //获取选中的起始位置
        int selectionStart = mTvSelect.getSelectionStart();
        int selectionEnd = mTvSelect.getSelectionEnd();
        Log.i(TAG,"selectionStart="+selectionStart+",selectionEnd="+selectionEnd);
        //截取选中的文本
        String txt = mTvSelect.getText().toString();
        String substring = txt.substring(selectionStart, selectionEnd);
        Log.i(TAG,"substring="+substring);
        //将选中的文本放到剪切板
        cbs.setPrimaryClip(ClipData.newPlainText(null,substring));
        //如果是复制就不往下操作了
        if (mode==SelectMode.COPY)
            return txt;
        //把剪切后的数据替换""
        txt = txt.replace(substring, "");
        return txt;
    }

    /**
     * 用枚举来区分是复制还是剪切
     */
    public enum SelectMode{
        COPY,CUT;
    }

这里我把兼容低版本没有做,API Level 11以前用的setText(),getText(),hasText()这三个方法做复制粘帖的操作(只限于对文本的操作);以后的API中废弃了以前的三个方法,通过ClipData对象来操作文本、Uri和Intent,用ClipboardManager.setPrimaryClip(ClipData data),ClipboardManager.getPrimaryClip()和hasPrimaryClip()代替前面的三个方法了。这里操作的就不是纯文本,而是复杂的对象了。

ClipData 的三个静态方法分别担任不同的工作(ClipData对象中包含一个或多个ClipData.Item对象)

  • ClipData.newPlainText(“Label”, “Content”)创建普通字符型ClipData
  • ClipData.newRawUri(“Label”, Uri.parse(“https://www.baidu.com/“)) 创建URL型ClipData
  • ClipData.newIntent(“Label”, intent)创建Intent型ClipData

粘帖


                  //获取剪切班管理者
                    ClipboardManager cbs = (ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE);
                    if (cbs.hasPrimaryClip()){
                        mTvSelect.setText(cbs.getPrimaryClip().getItemAt(0).getText());
                    }

基本操作就OK了,我把完整的Java代码贴一下。

/**
 * 描述:文本的选中模式的使用
 * 开发者:开发者的乐趣JRT
 * 创建时间:2017-3-12 12:29
 * CSDN地址:http://blog.csdn.net/Jiang_Rong_Tao/article
 * E-mail:jrtxb520@163.com
 **/
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private EditText mTvSelect;
    private MainActivity mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext =this;
        init();
    }
    private void init() {
        mTvSelect = (EditText) findViewById(R.id.tv_select);
        mTvSelect.setCustomSelectionActionModeCallback(new MyActionModeCallback());
    }
    private class MyActionModeCallback implements ActionMode.Callback {
        private Menu mMenu;
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            MenuInflater menuInflater = actionMode.getMenuInflater();
            menuInflater.inflate(R.menu.menu,menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
           //菜单创建完成以后获取到其对象,便于后续操作
            this.mMenu=menu;
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
            switch (menuItem.getItemId()){
                case R.id.it_all:
                    //全选
                    mTvSelect.selectAll();
                    Toast.makeText(mContext, "完成全选", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.it_copy:
                    String selectText = getSelectText(SelectMode.COPY);
                    //setText(selectText)是为了后面的this.mMenu.close()起作用
                    mTvSelect.setText(selectText);
                    Toast.makeText(mContext, "选中的内容已复制到剪切板", Toast.LENGTH_SHORT).show();
                    this.mMenu.close();
                    break;
                case R.id.it_cut:
                    //剪切
                    String txt = getSelectText(SelectMode.CUT);
                    mTvSelect.setText(txt);
                    Toast.makeText(mContext, "选中的内容已剪切到剪切板", Toast.LENGTH_SHORT).show();
                    this.mMenu.close();
                    break;

                case R.id.it_paste:
                    //获取剪切班管理者
                    ClipboardManager cbs = (ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE);
                    if (cbs.hasPrimaryClip()){
                        mTvSelect.setText(cbs.getPrimaryClip().getItemAt(0).getText());
                    }
                    this.mMenu.close();
                    break;
            }
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode actionMode) {

        }
    }

    /**
     *  统一处理复制和剪切的操作
     * @param mode 用来区别是复制还是剪切
     * @return
     */
    private String getSelectText(SelectMode mode) {
        //获取剪切班管理者
        ClipboardManager cbs = (ClipboardManager) mContext.getSystemService(CLIPBOARD_SERVICE);
        //获取选中的起始位置
        int selectionStart = mTvSelect.getSelectionStart();
        int selectionEnd = mTvSelect.getSelectionEnd();
        Log.i(TAG,"selectionStart="+selectionStart+",selectionEnd="+selectionEnd);
        //截取选中的文本
        String txt = mTvSelect.getText().toString();
        String substring = txt.substring(selectionStart, selectionEnd);
        Log.i(TAG,"substring="+substring);
        //将选中的文本放到剪切板
        cbs.setPrimaryClip(ClipData.newPlainText(null,substring));
        //如果是复制就不往下操作了
        if (mode==SelectMode.COPY)
            return txt;
        txt = txt.replace(substring, "");
        return txt;
    }

    /**
     * 用枚举来区分是复制还是剪切
     */
    public enum SelectMode{
        COPY,CUT;
    }
}

注意:这里this.mMenu.close()有个细节,如果单纯的调用close方法是不起作用的,必须EditText的文本有所变化

  • 如果不重新设置EditText的文本,则menu的close方法不管用
    菜单不能关闭的效果
  • 重新设置文本后
    菜单关闭的效果

总结


基本的操作就到此结束了,EditText的UI和选中后的光标也有点抽,这些都是可以自定义改变的,具体操作,自行Search。

github:源码下载

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
实现长按Webview页面文字自定义复制全选、分享、搜索、翻译功能可以通过以下步骤: 1. 在Webview中注册长按事件,获取长按的位置和选中文本。 2. 创建一个弹出菜单,添加复制全选、分享、搜索、翻译等操作项。 3. 根据用户选择的操作项进行相应的处理。 下面是具体的实现代码: ``` // 注册长按事件 webView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { HitTestResult result = webView.getHitTestResult(); if (result.getType() == HitTestResult.SRC_ANCHOR_TYPE) { // 如果是链接,则不处理 return false; } // 获取长按的位置和选中文本 final int x = result.getX(); final int y = result.getY(); final String text = result.getExtra(); // 创建弹出菜单 PopupMenu popupMenu = new PopupMenu(MainActivity.this, webView); popupMenu.getMenuInflater().inflate(R.menu.popup_menu, popupMenu.getMenu()); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.copy: // 复制文本 ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); cm.setPrimaryClip(ClipData.newPlainText("text", text)); Toast.makeText(MainActivity.this, "已复制到剪贴板", Toast.LENGTH_SHORT).show(); break; case R.id.select_all: // 全选文本 webView.selectAll(); break; case R.id.share: // 分享文本 Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_TEXT, text); startActivity(Intent.createChooser(shareIntent, "分享到")); break; case R.id.search: // 搜索文本 Intent searchIntent = new Intent(Intent.ACTION_WEB_SEARCH); searchIntent.putExtra(SearchManager.QUERY, text); startActivity(searchIntent); break; case R.id.translate: // 翻译文本 Intent translateIntent = new Intent(Intent.ACTION_VIEW); translateIntent.setData(Uri.parse("https://translate.google.com/#auto/zh-CN/" + text)); startActivity(translateIntent); break; } return true; } }); popupMenu.show(); return true; } }); ``` 其中,`R.menu.popup_menu`是菜单的布局文件,可以通过XML定义菜单项: ``` <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/copy" android:title="复制" /> <item android:id="@+id/select_all" android:title="全选" /> <item android:id="@+id/share" android:title="分享" /> <item android:id="@+id/search" android:title="搜索" /> <item android:id="@+id/translate" android:title="翻译" /> </menu> ``` 这样就可以实现长按Webview页面文字自定义复制全选、分享、搜索、翻译功能了。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值