Custom cut/copy action bar for EditText that shows text selection handles
Mam aplikację, w której chcę być w stanie wyświetlić widok tekstu (lub EditText), który pozwala użytkownikowi wybrać jakiś tekst, a następnie nacisnąć przycisk, aby coś zrobić z tym tekstem. Zaimplementowanie tego w wersjach Androida przed Honeycomb nie jest problemem, ale na Honeycomb i powyżej domyślną akcją długiego naciśnięcia jest pokazanie paska akcji z opcjami Kopiuj/Wytnij/Wklej. Mogę przechwycić długie naciśnięcie, aby pokazać własny pasek akcji, ale wtedy nie wyświetlają się uchwyty wyboru tekstu.
Once I uruchomiłem własny tryb ActionMode jak wyświetlić uchwyty wyboru tekstu?
Oto kod, którego używam do uruchomienia ActionMode, który działa, ale nie ma wyświetlanych uchwytów wyboru tekstu:
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;
}
}
3 answers
Wymyśliłem odpowiedź na własne pytanie; TextView (a więc EditText) ma metodę setCustomSelectionActionModeCallback()
, która powinna być używana zamiast startActionMode()
. Umożliwia To dostosowanie menu używanego przez TextView do wyboru tekstu. Przykładowy kod:
bodyView.setCustomSelectionActionModeCallback(new StyleCallback());
Gdzie StyleCallback dostosowuje menu wyboru tekstu, usuwając Zaznacz wszystko i dodając kilka akcji stylizacji:
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 dla dodatków do menu to:
<?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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-16 10:48:03
Powyższe rozwiązanie jest dobre, jeśli chcesz dostosować opcje na pasku akcji. Ale jeśli chcesz nadpisać pasek akcji kopiuj / wklej itp., poniżej znajduje się kod...
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;
}
});
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 07:03:07
Najprostszym sposobem na to jest dodanie linii w głównym stylu motywu, który zdefiniowałeś w znaczniku application
z AndroidManifest
. Otwórz swój styl motywu i dodaj:
<item name="actionModeBackground">@color/your_color</item>
Lub
<item name="android:actionModeBackground">@color/your_color</item>
Na przykład: Mój styl motywu, który zdefiniowałem:
<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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-11 08:16:41