1

現在、テキスト内にプレースホルダーがある可能性のある複数行の編集テキストに取り組んでいます。これらのプレースホルダーの変更を回避するために、カーソル位置がそのようなプレースホルダー内にあるかどうかをチェックする onClickListener を EditText ウィジェットに追加しました。その場合、完全に削除する以外の変更を防ぐために、プレースホルダーを選択する必要があります。

これは私の Android 2.3 デバイスでは問題なく動作しますが、Android 4.x では onClick イベントの後に選択が変更され、選択なしでプレースホルダーの先頭にカーソルが表示されます。

onClickListener のソースの下。

protected void textClickListener(EditText v) { 
    Pattern p = Pattern.compile(placeholderRegex);
    Matcher matcher = p.matcher(v.getText());
    int sel_start = v.getSelectionStart();
    int sel_end = v.getSelectionEnd();
    if (sel_start == -1) {
        return;
    }
    while (matcher.find()) {
        int pattern_start = matcher.start();
        int pattern_end = pattern_start + 25;
        if (pattern_start > sel_end) {
            continue;
        }
        if (pattern_end < sel_start) {
            continue;
        }
        v.setSelection(Math.min(sel_start, pattern_start), Math.max(sel_end, pattern_end));
        return;
    }
}

このコードは正常に動作し、正しい値で setSelection が呼び出され、選択が実際に設定されます。Selection.setSelection メソッドにブレークポイントを設定したところ、それが android.widget.editor の内部クラスである PositionListener から呼び出され、選択の長さが 0 に設定されていることがわかりました。以下は、この setSelection 呼び出しのスタック トレースです。

Selection.setSelection(Spannable, int) line: 87 
Editor$InsertionHandleView.updateSelection(int) line: 3271  
Editor$InsertionHandleView(Editor$HandleView).positionAtCursorOffset(int, boolean) line: 3045   
Editor$InsertionHandleView(Editor$HandleView).updatePosition(int, int, boolean, boolean) line: 3064 
Editor$PositionListener.onPreDraw() line: 2047  
ViewTreeObserver.dispatchOnPreDraw() line: 671  
ViewRootImpl.performTraversals() line: 1820 
ViewRootImpl.doTraversal() line: 1000   
ViewRootImpl$TraversalRunnable.run() line: 4214 
Choreographer$CallbackRecord.run(long) line: 725    
Choreographer.doCallbacks(int, long) line: 555  
Choreographer.doFrame(long, int) line: 525  
Choreographer$FrameDisplayEventReceiver.run() line: 711 
Handler.handleCallback(Message) line: 615   
Choreographer$FrameHandler(Handler).dispatchMessage(Message) line: 92   
Looper.loop() line: 137 
ActivityThread.main(String[]) line: 4745    
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
Method.invoke(Object, Object...) line: 511  
ZygoteInit$MethodAndArgsCaller.run() line: 786  
ZygoteInit.main(String[]) line: 553 
NativeStart.main(String[]) line: not available [native method]

これを防ぐ方法、またはこの PositionListener アクションの後に選択を設定する方法はありますか?

4

1 に答える 1

1

質問から移行

最後に、で選択を変更する必要があることがわかりましたOnTouchListenerACTION_DOWNさらに複雑にするために、そのリスナー ( 、 )の両方の呼び出しで選択を変更する必要がありますACTION_UP。(パフォーマンス上の理由で行ったように)一度だけ実行しても機能しません。したがって、最終的に機能するコードは次のとおりです。

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
protected boolean textTouchListener(EditText v, MotionEvent event) {
    placeholder_selected = false;
    Pattern p = Pattern.compile(placeHolderRegex);
    Matcher matcher = p.matcher(v.getText());
    int click_position = v.getOffsetForPosition(event.getX(), event.getY());
    int sel_start = click_position;
    int sel_end = click_position;
    if (sel_start == -1) {
        return false;
    }
    while (matcher.find()) {
        int pattern_start = matcher.start();
        int pattern_end = pattern_start + 25;
        if (pattern_start > sel_end) {
            continue;
        }
        if (pattern_end < sel_start) {
            continue;
        }
        v.setSelection(Math.min(sel_start, pattern_start), Math.max(sel_end, pattern_end));
        placeholder_selected = true;
        return true;
    }
    return false;
}

このメソッドは 11 未満の API レベル (Honeycomb) では使用できないOnClickListenerため、互換性の理由から が引き続き必要です。getOffsetForPosition使用する API に応じて、両方のリスナーの一方のみを実行する必要があります。

于 2012-11-21T01:26:29.927 に答える