私の目標は、カーソルをより簡単に移動させるためのテキスト選択ハンドラーだけで、コンテキストメニューやポップアップがない、派手な機能を持たないEditText
を持つことです。
このソリューション のように、ActionModeコールバックイベントを使用して、テキスト編集機能のアクションバーの外観(コピー/貼り付けなど)を無効にしました。
フィールドにテキストが存在し、テキスト内でクリックが発生すると、中央の中間テキスト選択ハンドル(下の画像を参照)が引き続き表示されます。すごい!私はこの振る舞いを保ちたいです。私が望んでいないのは、テキスト選択ハンドル自体をクリックしたときに表示される「貼り付け」メニューです。
また、スタイルXMLでAndroid:longClickable="false"
を設定して、EditTextのロングクリック入力を無効にしました。ロングクリックを無効にすると、マウスがクリックされた状態(ロングタッチ)で[貼り付け/置換]メニューが表示されなくなりますが、テキスト内でマウスをクリック(シングルタッチ)すると、テキスト選択ハンドルが表示され、テキスト選択ハンドル自体をクリックすると、「貼り付け」メニューオプションが表示されます(クリップボードにテキストがある場合)。これは私が防止しようとしているものです。
ソースから見ることができるものから、ActionPopupWindow
はPASTE/REPLACEオプションでポップアップするものです。 ActionPopupWindowは、パブリッククラスAndroid.widget.Editor ...内のプライベート抽象クラスHandleViewの保護された変数(mActionPopupWindow)です。
クリップボードサービスを無効にするか、Androidソースコードを編集する以外に、これが表示されないようにする方法はありますか?Android:textSelectHandleWindowStyle
の新しいスタイルを定義して設定しましたAndroid:visibility
をgone
に変更しましたが、機能しませんでした(それ以外の場合に表示されるはずだったアプリがしばらくフリーズしました)。
解決策:isSuggestionsEnabled
のcanPaste
およびEditText
をオーバーライドします。
簡単な解決策として、以下のクラスをコピーします-このクラスは EditText
クラスをオーバーライドし、それに応じてすべてのイベントをブロックします。
ざらざらした詳細については、読み続けてください。
解決策は、(ドキュメント化されていない)_Android.widget.Editor
_クラスの show()
メソッドにPASTE/REPLACEメニューが表示されないようにすることです。メニューが表示される前に、if (!canPaste && !canSuggest) return;
のチェックが行われます。これらの変数を設定する基礎として使用される2つのメソッドは、両方ともEditText
クラスにあります。
isSuggestionsEnabled()
は public であるため、オーバーライドできます。canPaste()
はそうではないため、派生クラスで 同じ名前の関数を導入 によって非表示にする必要があります。したがって、これらの更新を setCustomSelectionActionModeCallback および disabled long-click を持つクラスに組み込むと、すべての編集を防ぐための完全なクラスになります(ただし、 テキスト選択ハンドラー )カーソルを制御するため:
_package com.cjbs.widgets;
import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.ActionMode;
import Android.view.Menu;
import Android.view.MenuItem;
import Android.widget.EditText;
/**
* This is a thin veneer over EditText, with copy/paste/spell-check removed.
*/
public class NoMenuEditText extends EditText
{
private final Context context;
/** This is a replacement method for the base TextView class' method of the same name. This
* method is used in hidden class Android.widget.Editor to determine whether the PASTE/REPLACE popup
* appears when triggered from the text insertion handle. Returning false forces this window
* to never appear.
* @return false
*/
boolean canPaste()
{
return false;
}
/** This is a replacement method for the base TextView class' method of the same name. This method
* is used in hidden class Android.widget.Editor to determine whether the PASTE/REPLACE popup
* appears when triggered from the text insertion handle. Returning false forces this window
* to never appear.
* @return false
*/
@Override
public boolean isSuggestionsEnabled()
{
return false;
}
public NoMenuEditText(Context context)
{
super(context);
this.context = context;
init();
}
public NoMenuEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
init();
}
public NoMenuEditText(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
this.context = context;
init();
}
private void init()
{
this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
this.setLongClickable(false);
}
/**
* Prevents the action bar (top horizontal bar with cut, copy, paste, etc.) from appearing
* by intercepting the callback that would cause it to be created, and returning false.
*/
private class ActionModeCallbackInterceptor implements ActionMode.Callback
{
private final String TAG = NoMenuEditText.class.getSimpleName();
public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; }
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; }
public void onDestroyActionMode(ActionMode mode) {}
}
}
_
これをAndroid v4.4.2およびv4.4.3でテストしました。
または単に使用する
yourEditText.setLongClickable(false);
またはXMLで
Android:longClickable="false"
更新
実際にユーザーは、テキスト選択ハンドル自体をdisableにしたい
1。シェイプを作成する(handle.xml)
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle" >
<size
Android:height="0dp"
Android:width="0dp" />
</shape>
2。EditTextで
Android:textSelectHandle="@drawable/handle"
「貼り付け」ポップアップを無効にするハックを次に示します。 EditText
メソッドをオーバーライドする必要があります。
@Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
このソリューションは、承認済みの回答とは異なり、Androidの新しいバージョンでも動作します。
メニューポップアップを非表示にする方法が見つかりませんが、ユーザーがメニューをタップすると、貼り付けを無効にすることができます
カスタムEditText
を作成し、onTextContextMenuItem
メソッドをオーバーライドし、Android.R.id.paste
およびAndroid.R.id.pasteAsPlainText
メニューIDに対してfalseを返します。
@Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case Android.R.id.paste:
case Android.R.id.pasteAsPlainText:
return false;
}
return super.onTextContextMenuItem(id);
}
青いビュー(挿入コントローラー)がまったく表示されないときに別のソリューションが見つかりました。 Editorクラスのターゲットブールフィールドを設定するためにリフレクションを使用しました。詳細については、Android.widget.EditorおよびAndroid.widget.TextViewをご覧ください。
次のコードをカスタムEditTextに追加します(このトピックの以前のすべてのコードと共に):
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// setInsertionDisabled when user touches the view
this.setInsertionDisabled();
}
return super.onTouchEvent(event);
}
/**
* This method sets TextView#Editor#mInsertionControllerEnabled field to false
* to return false from the Editor#hasInsertionController() method to PREVENT showing
* of the insertionController from EditText
* The Editor#hasInsertionController() method is called in Editor#onTouchUpEvent(MotionEvent event) method.
*/
private void setInsertionDisabled() {
try {
Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editorObject = editorField.get(this);
Class editorClass = Class.forName("Android.widget.Editor");
Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
mInsertionControllerEnabledField.setAccessible(true);
mInsertionControllerEnabledField.set(editorObject, false);
}
catch (Exception ignored) {
// ignore exception here
}
}
また、ターゲットメソッドを呼び出すには、onTouch()よりも良い場所を見つけることができます。
テスト済みAndroid 5.1
PASTEの提案を削除する必要がある場合は、長いクリックの前にクリップボードをクリアしてください。
//class
ClipboardManager clipboard;
//oncreate
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
Use this in Java file
if (Android.os.Build.VERSION.SDK_INT < 11) {
editText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
@Override`enter code here`
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
menu.clear();
}
});
} else {
editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
public void onDestroyActionMode(ActionMode mode) {
// TODO Auto-generated method stub
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
public boolean onActionItemClicked(ActionMode mode,
MenuItem item) {
// TODO Auto-generated method stub
return false;
}`enter code here`
});
}
With this code also add Android:textSelectHandle="@drawable/handle"
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle" >
<size
Android:height="0dp"
Android:width="0dp" />
</shape>
By Using these two combinations my problem is solved.
1つのメソッドをオーバーライドするだけです:
@Override
protected MovementMethod getDefaultMovementMethod() {
// we don't need arrow key, return null will also disable the copy/paste/cut pop-up menu.
return null;
}
シンプルでありながら信頼できる方法を見つけました。これは、タッチイベントがデフォルトコードに下線を引くことを防ぐために、タッチイベントを消費するという考え方です。
maskedEditText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
focusAndShowKeyboard(view.getContext(), maskedEditText);
// Consume the event.
return true;
}
});
private static void focusAndShowKeyboard(Context context, EditText editText) {
editText.requestFocus();
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
点滅カーソルはテキストの最後にまだ表示されていることに注意してください。ただスクリーンショットはそれをキャプチャすることができません。
上記の解決策はどれも私にとってはうまくいきませんでした。私は解決策を実行することができました(後の説明)。これは、他のすべての操作を有効に保ちながら、EditTextへの貼り付けを無効にしました。
主に、EditTextの実装でこのメソッドをオーバーライドする必要があります。
@Override
public boolean onTextContextMenuItem (int id) {
if (id == Android.R.id.paste) return false;
return super.onTextContextMenuItem(id);
}
したがって、EditTextコードの調査では、すべてのチェック、貼り付け(およびEditText上のすべてのContextMenu
アクション)がonTextContextMenuItem
というメソッドで行われます。
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));
}
switch (id) {
case ID_SELECT_ALL:
// This does not enter text selection mode. Text is highlighted, so that it can be
// bulk edited, like selectAllOnFocus does. Returns true even if text is empty.
selectAllText();
return true;
case ID_PASTE:
paste(min, max);
return true;
case ID_CUT:
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
deleteText_internal(min, max);
stopSelectionActionMode();
return true;
case ID_COPY:
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
stopSelectionActionMode();
return true;
}
return false;
}
気づいた場合、貼り付けはid == ID_PASTE
ので、EditTextコードをもう一度見てください。
static final int ID_PASTE = Android.R.id.paste;