9

我想实现一个自定义文本界面,触摸+拖动选择文本并且键盘没有被抬起,这与长按打开 CCP 菜单和键盘的默认行为形成对比。我的理解表明我需要这种方法:

onTouchEvent(event){
  case touch_down:
    get START text position

  case drag
    get END text position
    set selection range from START to END
}

我已经了解了所有关于 getSelectStart() 和设置范围等的各种方法,但我找不到如何根据触摸事件 getX() 和 getY() 获取文本位置。有没有办法做到这一点?我已经在其他办公应用程序中看到了我想要的行为。

另外,在手动请求之前,我将如何阻止键盘出现?

4

5 回答 5

12

"mText.setInputType(InputType.TYPE_NULL)" 将抑制软键盘,但它也会在 Android 3.0 及更高版本下禁用 EditText 框中的闪烁光标。我编写了一个 onTouchListener 并返回 true 以禁用键盘,然后必须从运动事件中获取触摸位置以将光标设置到正确的位置。您可以在 ACTION_MOVE 运动事件上​​使用它来选择要拖动的文本。

这是我使用的代码:

  mText = (EditText) findViewById(R.id.editText1);
  OnTouchListener otl = new OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
      switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
          Layout layout = ((EditText) v).getLayout();
          float x = event.getX() + mText.getScrollX();
          int offset = layout.getOffsetForHorizontal(0, x);
          if(offset>0)
              if(x>layout.getLineMax(0))
                  mText.setSelection(offset);     // touch was at end of text
              else
                  mText.setSelection(offset - 1);
          break;
          }
      return true;
      }
  };
  mText.setOnTouchListener(otl);
于 2013-01-06T18:09:50.843 回答
11

感谢 Waine Kail 分享开始代码,但它只处理了事件的“x”轴。对于多行EditText,您还必须:

1- 计算垂直位置 (y):
2- 通过垂直位置获取行偏移
3- 使用行和水平位置获取文本偏移

EditText et = (EditText) findViewById(R.id.editText1);

long offset = -1; //text position will be corrected when touching.

et.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
      case MotionEvent.ACTION_UP:
          Layout layout = ((EditText) v).getLayout();
          float x = event.getX() + et.getScrollX();
          float y = event.getY() + et.getScrollY();            
          int line = layout.getLineForVertical((int) y);                      

 // Here is what you wanted:

          offset = layout.getOffsetForHorizontal( line,  x);

          break;
        }
    return false;
}
});
于 2013-04-24T04:44:10.330 回答
6

I'm facing the same issue too. And when I tried to use "int offset = layout.getOffsetForHorizontal(0, x);" like Wayne Kail said, also got NPE in this line. So I tried and in the end write like this:

mText = (EditText) findViewById(R.id.editText1);
OnTouchListener otl = new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      EditText editText = (EditText) v;
      float x = event.getX();
      float y = event.getY();
      int touchPosition = editText.getOffsetForPosition(x, y);
      if (touchPosition>0){
          editText.setSelection(touchPosition);
      }
      return true;
    }
};
mText.setOnTouchListener(otl); 
于 2015-09-10T08:30:51.763 回答
2

对于我的应用程序,我需要在 touchlistener 中获取位置,但上述解决方案似乎没有给出精确的位置。对我来说,它通常相对于文本光标偏离 1-2 个字符。下面的代码解决了这个问题。让它工作的关键是使用 post() 将代码推迟到光标位置更新之后。这样我得到的位置保证和EditText的一致,代码也更简单。

setOnTouchListener(new OnTouchListener()
    {
    @Override
    public boolean onTouch(View view, MotionEvent event)
        {
        if(event.getAction()==MotionEvent.ACTION_UP)
            {
            //At this point the selection has not been updated. So post an
            //event at the end of the event queue to check where cursor
            //has been moved
            post(new Runnable()
                {
                public void run()
                    {
                    Editable sb=getText();
                    int currentPos=getSelectionStart();
                    //TODO
                    }
                });
            }
        return false;
        }
    });
于 2013-09-20T14:32:00.087 回答
0

在 EditText 中,onTouch 事件调用了两次:对于 ACTION_DOWN 和 ACTION_UP。这就是 getLayout 导致 null 的原因。我将在这里发布有效的代码,需要验证和对待

@Override
@SuppressLint("ClickableViewAccessibility")
public boolean onTouch(View view, MotionEvent motionEvent) {
    final EditText editText = (EditText) view;
    final int editTextSelectionStart = editText.getSelectionStart();
    final int editTextSelectionEnd = editText.getSelectionEnd();
    final Layout layout = editText.getLayout();
    final int inType = editText.getInputType(); // Backup the input type.
    editText.setInputType(InputType.TYPE_NULL); // Disable standard keyboard.
    editText.onTouchEvent(motionEvent); // Call native handler.
    editText.setInputType(inType);// Restore input type.

    switch (motionEvent.getAction()) {
        case MotionEvent.ACTION_DOWN:
            float x = motionEvent.getX() + editText.getScrollX();
            if (layout != null) {
                int offset = layout.getOffsetForHorizontal(0, x);
                if (offset > 0) {
                    if (x > layout.getLineMax(0)) {
                        editText.setSelection(offset);
                    } else {
                        editText.setSelection(offset - 1);
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            editText.setSelection(editTextSelectionStart, editTextSelectionEnd);
        break;
    }

    return true; // Consume touch event.
}
于 2020-10-02T19:14:28.247 回答