1

我目前正在处理可能在其文本中包含占位符的多行编辑文本。为了避免修改这些占位符,我在 EditText 小部件中添加了一个 onClickListener,它检查光标位置是否在这样的占位符内。在这种情况下,应选择占位符,以防止除完全删除之外的任何修改。

这在我的 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 方法上设置了一个断点,发现它是从 PositionListener 调用的,它是 android.widget.editor 的一个内部类,它将选择长度设置为 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

从问题迁移

最后我发现,你必须修改OnTouchListener. 更复杂的是,您必须修改该侦听器 ( ACTION_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;
}

OnClickListener出于兼容性原因,仍然需要该方法,因为该方法不适getOffsetForPosition用于低于 11 的 API 级别(Honeycomb)。根据使用的 API,只需执行两个侦听器中的一个。

于 2012-11-21T01:26:29.927 回答