android:如何从触摸事件中获取文本位置

android:如何从触摸事件中获取文本位置,android,android-edittext,selection,Android,Android Edittext,Selection,我想实现一个定制的文本界面,通过触摸+拖动选择文本,并且键盘不会弹出,这与长时间点击打开CCP菜单和键盘的默认行为形成对比。我的理解表明我需要这种方法: onTouchEvent(event){ case touch_down: get START text position case drag get END text position set selection range from START to END } 我已经了解了所有关于getSelectSt

我想实现一个定制的文本界面,通过触摸+拖动选择文本,并且键盘不会弹出,这与长时间点击打开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()获取文本位置。有没有办法做到这一点?我在其他office应用程序中看到了我想要的行为

另外,在手动请求之前,如何停止键盘显示?

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

以下是我使用的代码:

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

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

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

对于我的应用程序,我需要获得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;
        }
    });

我也面临同样的问题。当我尝试使用“int offset=layout.getOffsetForHorizontal(0,x);”时,就像前面所说的,这一行也得到了NPE。所以我试着最后写下这样的话:

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

在EditText中,中的onTouch事件被调用两次:for ACTION\u DOWN和ACTION\u 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.
}

谢谢这个帮助我…:)我得到布局的空指针异常,为什么?我不知道。对于布局,我做过类似的事情。ViewTreeObserver vto=edittext.getViewTreeObserver();vto.addOnGlobalLayoutListener(新ViewTreeObserver.OnGlobalLayoutListener(){@Override public void onGlobalLayout(){layout=edittext.getLayout();}});第行出现空指针异常:“int offset=layout.getOffsetForHorizontal(0,x);”