Extracting words from TextView after click/press on them - android

is there any easy way to select whole words from TextView by touching them? This functionality is in dictionary app ColorDict.
Search for word "word"
Select word "theorem" and it now appears in the search box so I can search it faster by clicking on search.
I want to be able to select those words. That ScrollView which is on top is misleading. It appears after selecting "Select a word" in dialog which appears after long press on something in TextView (you can see word "theorem" on the bottom - long press on "theorem").
Thank you for suggestions.

Try setting this attribute to your TextView:
android:textIsSelectable="true"
EDIT:
private static final int MENU_ITEM_ID = 0x42;
private TextView targetTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
targetTextView = (TextView) findViewById(R.id.target_textview);
targetTextView.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// you can remove the default menu items if you wish
menu.removeItem(android.R.id.selectAll);
menu.removeItem(android.R.id.cut);
menu.removeItem(android.R.id.copy);
return true;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
/*
* called when the action mode is created. Here you can
* generate action buttons for this action mode.
* */
menu.add(0, MENU_ITEM_ID, 0, "Menu Item").setIcon(android.R.drawable.ic_dialog_alert);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
// called when the action mode is about to be destroyed
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_ID:
int start = targetTextView.getSelectionStart();
int end = targetTextView.getSelectionEnd();
CharSequence selectedText = targetTextView.getText().subSequence(start, end);
Toast.makeText(MainActivity.this, selectedText, Toast.LENGTH_SHORT).show();
mode.finish();
return true;
default:
break;
}
return false;
}
});
}

Related

Focus ListView Items on Button Click

Is it possible to focus the List View Items through any button click?
Like i want that when user click on Floating Action Button then the listview gets focused. I dont want to show checkbox type layout on button clicked. I just want to show the same like in the screenshot on Button click.
What i did is I put the listview onItemLongClick code in the button click blocks but it doesnot work.
fabButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
listViewMessages.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listViewMessages.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
tv.setText(listViewMessages.getCheckedItemCount()+ " Selected");
}
#Override
public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu:
}
});
mode.finish();
return true;
default:
return false;
}
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate the menu for the CAB
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.contextual, menu);
fabButton.setVisibility(View.INVISIBLE);
fabButtonn.setVisibility(View.VISIBLE);
fabButtonn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
for ( int i=0; i< messageListAdapter.getCount(); i++ ) {
listViewMessages.setItemChecked(i, true);
}
}
});
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
fabButton.setVisibility(View.VISIBLE);
fabButtonn.setVisibility(View.GONE);
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// Here you can perform updates to the CAB due to
// an invalidate() request
return false;
}
});
With this code if user clcik on button then he/she has too long press items again to focus the list items which is not what i want. I want to focus items right when button click. Any explanation or link provided will be helpful

Android ListView Single Choice Mode with Action Mode

I would like to create an app screen that include one ListView.
When the user performs long press on ListView item, I would like to show action mode. I implemented it with the following code and I got the result which I want.
One problem is that I would like to allow the user to select only one list item and select the context menu item in action mode to do the operation. The following code is allowed the user to select multiple list items.
Is android not support ListView.CHOICE_MODE_SINGLE_MODAL choice mode? I had spend a lot of time in Googling but can't find any reference to implement which allows a single choice mode with context action mode. Please help.
mTestListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mTestListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int position, long l, boolean value) {
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.context_menu_test_single_choice_mode, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_done:
Toast.makeText(getActivity(), "Done", Toast.LENGTH_SHORT).show();
actionMode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
}
Add this code in your method. This code will check item count. If count exceed more than one, it will remove other item except the last one.
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
int selectCount = mList.getCheckedItemCount();
if(selectCount > 1){
SparseBooleanArray checkarr = mList.getCheckedItemPositions();
for(int i=0;i<dataList.size();i++){
/*
check item is checked
and not the last item
* */
if(checkarr.get(i) && position != i){
mList.setItemChecked(i, false);
break;
}
}
}
}
I tried in my app. It works. :). Hope this will help you.

Popup Menu won't change its selected state

I have this code here, I created a popup menu when the user long-presses the "edit_text" view's area which displays a popup menu with "Red" "Yellow" radio button option which changes the background color of the "text_view", but I'm not sure why when I select the other option, like when red is currently selected, I select yellow and the other way around(I have the red option selected as the default state), the selected state does not change at all, red is still selected no matter how many times I press yellow. Could you guys help me with this please? Thank you very much.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit_text = (EditText)findViewById(R.id.edit_text_1);
text_view = (TextView)findViewById(R.id.textView1);
//==========_CREATE A POPUP MENU WHEN LONG-CLICK ON EDITTEXT AREA_==========\\
edit_text.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
final PopupMenu pop_up = new PopupMenu(getContext(), v);
getMenuInflater().inflate(R.menu.main, pop_up.getMenu());
//GROUP'S ID IS "group".
pop_up.getMenu().setGroupCheckable(R.id.group, true, true);
pop_up.show();
pop_up.setOnMenuItemClickListener(listener);
return true;
}
});
}
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case R.id.red:
text_view.setBackgroundColor(Color.RED);
if (!item.isChecked()) {
item.setChecked(true);
}
return true;
case R.id.yellow:
text_view.setBackgroundColor(Color.YELLOW);
if (!item.isChecked()) {
item.setChecked(true);
}
return true;
default:
return false;
}
}
};
protected Context getContext() {
return this;
}
Looks like there's some logical issue with your code. Based on the documentation:
When a checkable item is selected, the system calls your respective
item-selected callback method (such as onOptionsItemSelected()). It is
here that you must set the state of the checkbox, because a checkbox
or radio button does not change its state automatically.
It's easy to observe that yours onLongClick(View v) get called every time and so the menu gets created every long click again (with initial items states). To fix the issue you can store checked / unchecked state (or current color) some there and set item states properly every time in onLongClick(View v). Like the following:
public class MainActivity extends ActionBarActivity {
private static final String TAG = "MainActivity";
private TextView mText;
// For persistent storage SharedPreferences should be used instead of local variable
private int mColor = Color.RED;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText edit = (EditText) findViewById(R.id.edit_text_1);
mText = (TextView)findViewById(R.id.textView1);
mText.setBackgroundColor(mColor);
edit.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Log.d(TAG, "onLongClick");
final PopupMenu pop_up = new PopupMenu(MainActivity.this, v);
final Menu menu = pop_up.getMenu();
getMenuInflater().inflate(R.menu.popup_menu, menu);
//GROUP'S ID IS "group".
menu.setGroupCheckable(R.id.group, true, true);
pop_up.show();
switch(mColor) {
case Color.RED:
menu.findItem(R.id.yellow).setChecked(false);
menu.findItem(R.id.red).setChecked(true);
break;
case Color.YELLOW:
menu.findItem(R.id.red).setChecked(false);
menu.findItem(R.id.yellow).setChecked(true);
break;
default:
break;
}
pop_up.setOnMenuItemClickListener(mMenuItemClickListener);
return true;
}
});
}
final OnMenuItemClickListener mMenuItemClickListener = new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case R.id.red:
mText.setBackgroundColor(Color.RED);
mColor = Color.RED;
return true;
case R.id.yellow:
mText.setBackgroundColor(Color.YELLOW);
mColor = Color.YELLOW;
return true;
default:
return false;
}
}
};
Also, I'd suggest to checkout ContextMenu which provides slightly more convenient way for creating long-click context menus. Please note that documentation of ContextMenu from onCreateContextMenu() clearly states that menu in proper state should be populated by the app every time:
Called when a context menu for the view is about to be shown. Unlike
onCreateOptionsMenu(Menu), this will be called every time the context
menu is about to be shown and should be populated for the view (or
item inside the view for AdapterView subclasses, this can be found in
the menuInfo)).

Get Selected Text from TextView

I'm trying to get the text the user selected in a TextView,
i wan't to use the android:textIsSelectable="true" to allow my user copy/paste actions
However I don't have a clue as how to get the text once the action bar menu is displayed, the goal is to implement a Google book like behavior : you select a word and it gives you a definition.
I think what you're looking for is TextView.setCustomSelectionActionModeCallback. This will allow you to create your own ActionMode.Callback for when the text is selected. Then you can use TextView.getSelectionStart and TextView.getSelectionEnd to retrieve the selected text when your MenuItem is selected. Here's a quick example:
mTextView.setCustomSelectionActionModeCallback(new Callback() {
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// Remove the "select all" option
menu.removeItem(android.R.id.selectAll);
// Remove the "cut" option
menu.removeItem(android.R.id.cut);
// Remove the "copy all" option
menu.removeItem(android.R.id.copy);
return true;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Called when action mode is first created. The menu supplied
// will be used to generate action buttons for the action mode
// Here is an example MenuItem
menu.add(0, DEFINITION, 0, "Definition").setIcon(R.drawable.ic_action_book);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
// Called when an action mode is about to be exited and
// destroyed
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case DEFINITION:
int min = 0;
int max = mTextView.getText().length();
if (mTextView.isFocused()) {
final int selStart = mTextView.getSelectionStart();
final int selEnd = mTextView.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 = mTextView.getText().subSequence(min, max);
// Finish and close the ActionMode
mode.finish();
return true;
default:
break;
}
return false;
}
});
Results

Custom cut/copy action bar for EditText that shows text selection handles

I have an app where I want to be able to show a TextView (or EditText) that allows the user to select some text, then press a button to have something done with that text. Implementing this on Android versions prior to Honeycomb is no problem but on Honeycomb and above the default long-press action is to show an action bar with Copy/Cut/Paste options. I can intercept long-press to show my own action bar, but then I do not get the text selection handles displayed.
Once I have started my own ActionMode how do I get the text selection handles displayed?
Here is the code I'm using to start the ActionMode, which works except there are no text selection handles displayed:
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;
}
}
I figured out the answer to my own question; TextView (and therefore EditText) has a method setCustomSelectionActionModeCallback() which should be used instead of startActionMode(). Using this enables customisation of the menu used by TextView for text selection. Sample code:
bodyView.setCustomSelectionActionModeCallback(new StyleCallback());
where StyleCallback customises the text selection menu by removing Select All and adding some styling actions:
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) {
}
}
The XML for the menu additions is:
<?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>
Above solution is good if you want to customize the options in action bar.
But if you want to override action bar copy/Paste etc, below is the code...
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;
}
});
}
}
Easiest way to do it is to add a line in your main theme style which you have defined in your application tag of AndroidManifest. Open your theme style and add the following :
<item name="actionModeBackground">#color/your_color</item>
OR
<item name="android:actionModeBackground">#color/your_color</item>
For example:
My theme style which I have defined:
<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>

Categories

Resources