您的位置:首页 > 移动开发 > Android开发

Android textview获取选中的内容

2018-01-30 13:48 459 查看
1.首先设置textview可选:
android:textIsSelectable="true"


2.为textview设置监听
textView.setCustomSelectionActionModeCallback(callback2);

3.这个时候我们只要重写ActionMode.Callback2接口(需要判断sdk版本是否大于23,小于使用callback接口

private ActionMode.Callback2 callback2 = new ActionMode.Callback2()
{
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu)
{
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.text_selected, menu);
return true;
}

@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu)
{// 此方法用于清楚系统自带的meneitem(例如复制分享)
// MenuInflater menuInflater = actionMode.getMenuInflater();
// menu.clear();
// menuInflater.inflate(R.menu.text_selected,menu);
// return true;
return false;
}

@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem)
{
switch (menuItem.getItemId())
{
case R.id.toast:
{

Toast.makeText(MainActivity.this, "toast:" , Toast.LENGTH_SHORT).show();
break;
}

case R.id.finish:
{
MainActivity.this.finish();
break;
}

default:return false;
}
return true;
}

@Override
public void onDestroyActionMode(ActionMode actionMode)
{

}
};

4.要想获取所选中的内容,从callback2接口中看只有menu和menuitem,无法获取,但系统自带的有复制和剪切的功能,这时候就看一看系统是如何实现的。从设置监听的方法开始,见下面源码;监听事件被交由Edit这和类的mCustomSelectionActionModeCallback属性。
public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
createEditorIfNeeded();
mEditor.mCustomSelectionActionModeCallback = actionModeCallback;
}再看Editor这个类,对mCustomSelectionActionModeCallback属性操作的是getCustomCallback()方法,
private Callback getCustomCallback() {
return mHasSelection
? mCustomSelectionActionModeCallback
: mCustomInsertionActionModeCallback;
}
再看有哪些地方用到这个方法:Editor的内部类TextActionModeCallback
private class TextActionModeCallback extends ActionMode.Callback2 {
private final Path mSelectionPath = new Path();
private final RectF mSelectionBounds = new RectF();
private final boolean mHasSelection;

private int mHandleHeight;

public TextActionModeCallback(boolean hasSelection) {
mHasSelection = hasSelection;
if (mHasSelection) {
SelectionModifierCursorController selectionController = getSelectionController();
if (selectionController.mStartHandle == null) {
// As these are for initializing selectionController, hide() must be called.
selectionController.initDrawables();
selectionController.initHandles();
selectionController.hide();
}
mHandleHeight = Math.max(
mSelectHandleLeft.getMinimumHeight(),
mSelectHandleRight.getMinimumHeight());
} else {
InsertionPointCursorController insertionController = getInsertionController();
if (insertionController != null) {
insertionController.getHandle();
mHandleHeight = mSelectHandleCenter.getMinimumHeight();
}
}
}

@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle(null);
mode.setSubtitle(null);
mode.setTitleOptionalHint(true);
populateMenuWithItems(menu);

Callback customCallback = getCustomCallback();
if (customCallback != null) {
if (!customCallback.onCreateActionMode(mode, menu)) {
// The custom mode can choose to cancel the action mode, dismiss selection.
Selection.setSelection((Spannable) mTextView.getText(),
mTextView.getSelectionEnd());
return false;
}
}

if (mTextView.canProcessText()) {
mProcessTextIntentActionsHandler.onInitializeMenu(menu);
}

if (menu.hasVisibleItems() || mode.getCustomView() != null) {
mTextView.setHasTransientState(true);
return true;
} else {
return false;
}
}

private Callback getCustomCallback() { return mHasSelection ? mCustomSelectionActionModeCallback : mCustomInsertionActionModeCallback; }

private void populateMenuWithItems(Menu menu) {
if (mTextView.canCut()) {
menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT,
com.android.internal.R.string.cut).
setAlphabeticShortcut('x').
setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}

if (mTextView.canCopy()) {
menu.add(Menu.NONE, TextView.ID_COPY, MENU_ITEM_ORDER_COPY,
com.android.internal.R.string.copy).
setAlphabeticShortcut('c').
setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}

if (mTextView.canPaste()) {
menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE,
com.android.internal.R.string.paste).
setAlphabeticShortcut('v').
setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}

if (mTextView.canShare()) {
menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE,
com.android.internal.R.string.share).
setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}

updateSelectAllItem(menu);
updateReplaceItem(menu);
}

@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
updateSelectAllItem(menu);
updateReplaceItem(menu);

Callback customCallback = getCustomCallback();
if (customCallback != null) {
return customCallback.onPrepareActionMode(mode, menu);
}
return true;
}

private void updateSelectAllItem(Menu menu) {
boolean canSelectAll = mTextView.canSelectAllText();
boolean selectAllItemExists = menu.findItem(TextView.ID_SELECT_ALL) != null;
if (canSelectAll && !selectAllItemExists) {
menu.add(Menu.NONE, TextView.ID_SELECT_ALL, MENU_ITEM_ORDER_SELECT_ALL,
com.android.internal.R.string.selectAll)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
} else if (!canSelectAll && selectAllItemExists) {
menu.removeItem(TextView.ID_SELECT_ALL);
}
}

private void updateReplaceItem(Menu menu) {
boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions()
&& !(mTextView.isInExtractedMode() && mTextView.hasSelection());
boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null;
if (canReplace && !replaceItemExists) {
menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE,
com.android.internal.R.string.replace)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
} else if (!canReplace && replaceItemExists) {
menu.removeItem(TextView.ID_REPLACE);
}
}

@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
return true;
}
Callback customCallback = getCustomCallback();
if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
return true;
}
return mTextView.onTextContextMenuItem(item.getItemId());
}

@Override
public void onDestroyActionMode(ActionMode mode) {
Callback customCallback = getCustomCallback();
if (customCallback != null) {
customCallback.onDestroyActionMode(mode);
}

/*
* If we're ending this mode because we're detaching from a window,
* we still have selection state to preserve. Don't clear it, we'll
* bring back the selection mode when (if) we get reattached.
*/
if (!mPreserveDetachedSelection) {
Selection.setSelection((Spannable) mTextView.getText(),
mTextView.getSelectionEnd());
mTextView.setHasTransientState(false);
}

if (mSelectionModifierCursorC
acf7
ontroller != null) {
mSelectionModifierCursorController.hide();
}

mTextActionMode = null;
}

@Override
public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
if (!view.equals(mTextView) || mTextView.getLayout() == null) {
super.onGetContentRect(mode, view, outRect);
return;
}
if (mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
// We have a selection.
mSelectionPath.reset();
mTextView.getLayout().getSelectionPath(
mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mSelectionPath);
mSelectionPath.computeBounds(mSelectionBounds, true);
mSelectionBounds.bottom += mHandleHeight;
} else if (mCursorCount == 2) {
// We have a split cursor. In this case, we take the rectangle that includes both
// parts of the cursor to ensure we don't obscure either of them.
Rect firstCursorBounds = mCursorDrawable[0].getBounds();
Rect secondCursorBounds = mCursorDrawable[1].getBounds();
mSelectionBounds.set(
Math.min(firstCursorBounds.left, secondCursorBounds.left),
Math.min(firstCursorBounds.top, secondCursorBounds.top),
Math.max(firstCursorBounds.right, secondCursorBounds.right),
Math.max(firstCursorBounds.bottom, secondCursorBounds.bottom)
+ mHandleHeight);
} else {
// We have a single cursor.
Layout layout = getActiveLayout();
int line = layout.getLineForOffset(mTextView.getSelectionStart());
float primaryHorizontal =
layout.getPrimaryHorizontal(mTextView.getSelectionStart());
mSelectionBounds.set(
primaryHorizontal,
layout.getLineTop(line),
primaryHorizontal,
layout.getLineTop(line + 1) + mHandleHeight);
}
// Take TextView's padding and scroll into account.
int textHorizontalOffset = mTextView.viewportToContentHorizontalOffset();
int textVerticalOffset = mTextView.viewportToContentVerticalOffset();
outRect.set(
(int) Math.floor(mSelectionBounds.left + textHorizontalOffset),
(int) Math.floor(mSelectionBounds.top + textVerticalOffset),
(int) Math.ceil(mSelectionBounds.right + textHorizontalOffset),
(int) Math.ceil(mSelectionBounds.bottom + textVerticalOffset));
}
}
这个时候看到这个类是继承的callback2接口,该类是系统默认的监听类,此时我们需要找的是点击系统弹出的复制的点击执行哪些操作,所以我们重点看onActionItemClicked()方法
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
return true;
}
Callback customCallback = getCustomCallback();
if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
return true;
}
return mTextView.onTextContextMenuItem(item.getItemId());
}此时可以看到系统默认执行的mTextView.onTextContextMenuItem(item.getItemId()),这时我们进入这个方法
public boolean onTextContextMenuItem(int id) {
int min = 0;
int max = mText.length();

if (isFocused()) {
final int selStart = getSelectionStart();
final int selEnd = getSelectionEnd();

min = Math.max(0, Math.min(selStart, selEnd));
max = Math.max(0, Math.max(selStart, selEnd));
}.......
}
这个方法只需要看前半部分,min和max这两个值,这两个是截取的字符串所在原textview的text的位置,我们在点击我们的menu时获取这两个值,最后吐丝出来,源码见下:
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
{
private TextView textView;
private ActionMode.Callback2 callback2 = new ActionMode.Callback2()
{
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu)
{
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.text_selected, menu);
return true;
}

@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu)
{
// MenuInflater menuInflater = actionMode.getMenuInflater();
// menu.clear();
// menuInflater.inflate(R.menu.text_selected,menu);
// return true;
return false;
}

@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem)
{
switch (menuItem.getItemId())
{
case R.id.toast:
{
if (textView == null) return false;
int min = 0;
int max = textView.length();
if (textView.isFocused()) {
final int selStart = textView.getSelectionStart();
final int selEnd = textView.getSelectionEnd();

min = Math.max(0, Math.min(selStart, selEnd));
max = Math.max(0, Math.max(selStart, selEnd));
}

String content = String.valueOf(textView.getText().subSequence(min, max)) ;

Toast.makeText(MainActivity.this, "toast:" + content, Toast.LENGTH_SHORT).show();
break;
}

case R.id.finish:
{
MainActivity.this.finish();
break;
}

default:return false;
}
return true;
}

@Override
public void onDestroyActionMode(ActionMode actionMode)
{

}
};

@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.text);
textView.setCustomSelectionActionModeCallback(callback2);

}
}menu文件:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/toast"
android:title="吐丝"
/>

<item
android:id="@+id/finish"
android:title="finish"
/>
</menu>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息