【问题标题】:Custom cut/copy action bar for EditText that shows text selection handles用于显示文本选择句柄的 EditText 的自定义剪切/复制操作栏
【发布时间】:2012-10-21 06:04:30
【问题描述】:

我有一个应用程序,我希望能够显示一个 TextView(或 EditText),允许用户选择一些文本,然后按一个按钮来处理该文本。在 Honeycomb 之前的 Android 版本上实现这一点没有问题,但在 Honeycomb 及更高版本上,默认的长按操作是显示带有复制/剪切/粘贴选项的操作栏。我可以截取长按以显示我自己的操作栏,但是我没有显示文本选择句柄。

一旦我启动了自己的 ActionMode,我该如何显示文本选择句柄?

这是我用来启动 ActionMode 的代码,除了没有显示文本选择句柄之外,它可以工作:

public boolean onLongClick(View v) {
    if(actionMode == null)
        actionMode = startActionMode(new QuoteCallback());
    return true;
}

class QuoteCallback implements ActionMode.Callback {

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.quote, menu);
        return true;
    }

    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false;
    }

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch(item.getItemId()) {

        case R.id.quote:
            Log.d(TAG, "Selected menu");
            mode.finish();
            // here is where I would grab the selected text
            return true;
        }
        return false;
    }

    public void onDestroyActionMode(ActionMode mode) {
        actionMode = null;
    }
}

【问题讨论】:

  • 有什么方法可以在按钮点击上做到这一点,比如..我有一个文本视图,它是可选的。我想在单击按钮时启动与 wit 文本视图相关的默认操作模式(全选并复制)。我不能使用 textview 的 performLongClick (),因为它已经被覆盖了。有没有可能实现这一目标?我尝试了 startActionMode(),但它以空白操作栏打开..

标签: android android-edittext textview contextual-action-bar


【解决方案1】:

我找到了自己问题的答案; TextView(因此 EditText)有一个方法setCustomSelectionActionModeCallback(),应该使用它来代替startActionMode()。使用它可以自定义 TextView 用于文本选择的菜单。示例代码:

bodyView.setCustomSelectionActionModeCallback(new StyleCallback());

StyleCallback 通过移除 Select All 并添加一些样式操作来自定义文本选择菜单:

class StyleCallback implements ActionMode.Callback {

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        Log.d(TAG, "onCreateActionMode");
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.style, menu);
        menu.removeItem(android.R.id.selectAll);
        return true;
    }

    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false;
    }

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        Log.d(TAG, String.format("onActionItemClicked item=%s/%d", item.toString(), item.getItemId()));
        CharacterStyle cs;
        int start = bodyView.getSelectionStart();
        int end = bodyView.getSelectionEnd();
        SpannableStringBuilder ssb = new SpannableStringBuilder(bodyView.getText());

        switch(item.getItemId()) {

        case R.id.bold:
            cs = new StyleSpan(Typeface.BOLD);
            ssb.setSpan(cs, start, end, 1);
            bodyView.setText(ssb);
            return true;

        case R.id.italic:
            cs = new StyleSpan(Typeface.ITALIC);
            ssb.setSpan(cs, start, end, 1);
            bodyView.setText(ssb);
            return true;

        case R.id.underline:
            cs = new UnderlineSpan();
            ssb.setSpan(cs, start, end, 1);
            bodyView.setText(ssb);
            return true;
        }
        return false;
    }

    public void onDestroyActionMode(ActionMode mode) {
    }
}

菜单添加的 XML 是:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/italic"
          android:showAsAction="always"
          android:icon="@drawable/italic"
          android:title="Italic"/>
    <item android:id="@+id/bold"
          android:showAsAction="always"
          android:icon="@drawable/bold"
          android:title="Bold"/>
    <item android:id="@+id/underline"
          android:showAsAction="always"
          android:icon="@drawable/underline"
          android:title="Underline"/>
</menu>

【讨论】:

  • 我也在尝试相同的方法,但是因为我添加了更多项目,它们不适合手机上的 ActionBar。如果我让他们进入溢出菜单,只要我点击溢出按钮,ActionMode 就会被破坏。你遇到过同样的问题吗?有没有人解决它?
  • 我们是否能够覆盖复制、分享、网络搜索等方法?
  • @thisiscrazy4 不知道关于覆盖,但您可以删除任何预填充的菜单项,然后添加您自己的。
  • setCustomSelectionActionModeCallback() 仅适用于 TextView 和 EditText。 WebView 有什么用吗?
  • @Maniac 你找到解决这个问题的方法了吗?
【解决方案2】:

如果您想自定义操作栏中的选项,上述解决方案很好。 但是如果你想覆盖操作栏复制/粘贴等,下面是代码...

public class MainActivity extends Activity {
    EditText editText;
    private ClipboardManager myClipboard;
    private ClipData myClip;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        editText = (EditText) findViewById(R.id.editText3);

        myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
        editText = (EditText) findViewById(R.id.editText3);
        editText.setCustomSelectionActionModeCallback(new Callback() {

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                // TODO Auto-generated method stub

            }

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return true;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                // TODO Auto-generated method stub
                switch (item.getItemId()) {
                case android.R.id.copy:
                    int min = 0;
                    int max = editText.getText().length();
                    if (editText.isFocused()) {
                        final int selStart = editText.getSelectionStart();
                        final int selEnd = editText.getSelectionEnd();

                        min = Math.max(0, Math.min(selStart, selEnd));
                        max = Math.max(0, Math.max(selStart, selEnd));
                    }
                    // Perform your definition lookup with the selected text
                    final CharSequence selectedText = editText.getText()
                            .subSequence(min, max);
                    String text = selectedText.toString();

                    myClip = ClipData.newPlainText("text", text);
                    myClipboard.setPrimaryClip(myClip);
                    Toast.makeText(getApplicationContext(), "Text Copied",
                            Toast.LENGTH_SHORT).show();
                    // Finish and close the ActionMode
                    mode.finish();
                    return true;
                case android.R.id.cut:
                    // add your custom code to get cut functionality according
                    // to your requirement
                    return true;
                case android.R.id.paste:
                    // add your custom code to get paste functionality according
                    // to your requirement
                    return true;

                default:
                    break;
                }
                return false;
            }
        });         
    }    
}

【讨论】:

  • 我遵循了您的解决方案,并且几乎可以正常工作。唯一的问题是,并非我的所有自定义项目都显示在文本选择工具栏上。无论如何要实现一个水平列表吗?另一件事是复制/粘贴等默认功能,它们不再起作用,但是图标正在显示,是否可以再次对其进行反应?
【解决方案3】:

最简单的方法是在主主题样式中添加一行,您已在 AndroidManifestapplication 标记中定义该行。打开您的主题样式并添加以下内容:

<item name="actionModeBackground">@color/your_color</item>

<item name="android:actionModeBackground">@color/your_color</item>

例如: 我定义的主题风格:

<style name="AppTheme" parent="AppBaseTheme">

        <item name="calendarViewStyle">@style/Widget.Holo.CalendarView</item>
        <item name="android:actionBarStyle">@style/AppTheme1</item>
        <!-- below is the line you have to add -->
        <item name="android:actionModeBackground">@color/black_actionBar</item>
</style>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多