web-dev-qa-db-ja.com

EditText:テキスト選択ハンドラーのクリックイベントで[貼り付け/置換]メニューポップアップを無効にする

私の目標は、カーソルをより簡単に移動させるためのテキスト選択ハンドラーだけで、コンテキストメニューやポップアップがない、派手な機能を持たないEditTextを持つことです。

このソリューション のように、ActionModeコールバックイベントを使用して、テキスト編集機能のアクションバーの外観(コピー/貼り付けなど)を無効にしました。

フィールドにテキストが存在し、テキスト内でクリックが発生すると、中央の中間テキスト選択ハンドル(下の画像を参照)が引き続き表示されます。すごい!私はこの振る舞いを保ちたいです。私が望んでいないのは、テキスト選択ハンドル自体をクリックしたときに表示される「貼り付け」メニューです。

Text selection handle with paste menu

また、スタイルXMLでAndroid:longClickable="false"を設定して、EditTextのロングクリック入力を無効にしました。ロングクリックを無効にすると、マウスがクリックされた状態(ロングタッチ)で[貼り付け/置換]メニューが表示されなくなりますが、テキスト内でマウスをクリック(シングルタッチ)すると、テキスト選択ハンドルが表示され、テキスト選択ハンドル自体をクリックすると、「貼り付け」メニューオプションが表示されます(クリップボードにテキストがある場合)。これは私が防止しようとしているものです。

ソースから見ることができるものから、ActionPopupWindowはPASTE/REPLACEオプションでポップアップするものです。 ActionPopupWindowは、パブリッククラスAndroid.widget.Editor ...内のプライベート抽象クラスHandleViewの保護された変数(mActionPopupWindow)です。

クリップボードサービスを無効にするか、Androidソースコードを編集する以外に、これが表示されないようにする方法はありますか?Android:textSelectHandleWindowStyleの新しいスタイルを定義して設定しましたAndroid:visibilitygoneに変更しましたが、機能しませんでした(それ以外の場合に表示されるはずだったアプリがしばらくフリーズしました)。

18
CJBS

解決策:isSuggestionsEnabledcanPasteおよびEditTextをオーバーライドします。

簡単な解決策として、以下のクラスをコピーします-このクラスは EditText クラスをオーバーライドし、それに応じてすべてのイベントをブロックします。

ざらざらした詳細については、読み続けてください。

解決策は、(ドキュメント化されていない)_Android.widget.Editor_クラスの show() メソッドにPASTE/REPLACEメニューが表示されないようにすることです。メニューが表示される前に、if (!canPaste && !canSuggest) return;のチェックが行われます。これらの変数を設定する基礎として使用される2つのメソッドは、両方ともEditTextクラスにあります。

したがって、これらの更新を 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でテストしました。

20
CJBS

または単に使用する

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の新しいバージョンでも動作します。

7
Anton Tananaev

メニューポップアップを非表示にする方法が見つかりませんが、ユーザーがメニューをタップすると、貼り付けを無効にすることができます

カスタム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);
}
6
Libin

青いビュー(挿入コントローラー)がまったく表示されないときに別のソリューションが見つかりました。 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

5

PASTEの提案を削除する必要がある場合は、長いクリックの前にクリップボードをクリアしてください。

//class 
ClipboardManager clipboard;

//oncreate 
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
1
Mustafa
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
user1242611

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;
}

シンプルでありながら信頼できる方法を見つけました。これは、タッチイベントがデフォルトコードに下線を引くことを防ぐために、タッチイベントを消費するという考え方です。

  1. コピー/貼り付けポップアップを無効にします。
  2. テキスト選択ハンドラーを無効にします。
  3. テキストの最後にカーソルを表示しています。
  4. まだキーボードを表示しています。

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);
}

enter image description here

点滅カーソルはテキストの最後にまだ表示されていることに注意してください。ただスクリーンショットはそれをキャプチャすることができません。

0
Cheok Yan Cheng

上記の解決策はどれも私にとってはうまくいきませんでした。私は解決策を実行することができました(後の説明)。これは、他のすべての操作を有効に保ちながら、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;
0
Thalescm