Android开发:找出TextView里被点击处的字符和单词

原理,在TextView的onTouch事件里,取到点击的座标,再根据y座标,找出第几行,再根据行号,找出该行显示的字符串,然后根据x座标,计算点击处的字符。如果处理中文,找到即可,找英文单词的话,在该字符前后查找,看其是否属于同一个单词。 根据x座标行内查找这里,应该有更快的算法,因为我用的的最笨的方法,希望得到高人指点。

textView.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO 自动生成的方法存根
                switch(event.getAction())
                {
                case MotionEvent.ACTION_DOWN:
                    float x=event.getX();
                    float y=event.getY();
                    //因为行设置行间距后,文本在顶部,空白在底部,加上一半的行间距,可以实现与文本垂直居中一样的效果
                    y=y+textView.getLineSpacingExtra()/2-textView.getPaddingTop();
                    //在顶部padding空白处点击
                    if(y<0)
                        return false;
                    int singleLineHeight=textView.getLineHeight();
                    StaticLayout layout=(StaticLayout)textView.getLayout();

                    int lineNumber=Math.round(y/singleLineHeight)-1;
                    if(lineNumber<0)
                        lineNumber=0;
                    if(lineNumber>textView.getLineCount()-1)
                        lineNumber-=1;
                    int start=layout.getLineStart(lineNumber);
                    int end=layout.getLineEnd(lineNumber);

                    String str=textView.getText().toString().substring(start, end);
                     Paint paint=new Paint();
                    paint.setTextSize(textView.getTextSize());//设置字符大小
                    //单字节占宽度
                    int sigleByteWidth=(int)paint.measureText("1", 0, 1);

                    //减掉padding
                    float realX=x-textView.getPaddingLeft();
                    //在左侧padding空白处点击
                    if(realX<0)
                    {
                        return false;
                    }
                    //字符串可能的最大长度
                    //这里应该有更好更快的算法
                    int maxLength=(int)Math.floor(realX/sigleByteWidth);
                    //一般不会有字符显示超过两个1的宽度
                    int miniLenth=maxLength/2;
                    int strLength=str.length();
                    for(int i=strLength;i>=miniLenth;i--)
                    {
                        //字符串显示的宽度
                        float displayWidth=paint.measureText(str, 0, i);
                        if(Math.abs(displayWidth-realX)90&&clickChar<97)||clickChar>122)
                            {
                                return false;
                            }
                            //取单词,这段只针对英文,中文需要海量词库,太复杂了,前后看是不是空格或符号
                            StringBuilder sb=new StringBuilder();
                            sb.append(str.substring(i-1,i));
                            //查找前后的字符是否是同一个单词
                            String strBefore=str.substring(0,i-1);
                            String strAfter=str.substring(i,str.length());

                            String strBeforeReverse=reverseStr(strBefore);
                            Pattern p1=Pattern.compile("(^[a-zA-Z]+)");
                            //正则
                            Matcher m1=p1.matcher(strBeforeReverse);
                            if(m1.find())
                            {
                                sb.insert(0, reverseStr(m1.group(1)));
                            }

                            m1=p1.matcher(strAfter);
                            if(m1.find())
                            {
                                sb.append(m1.group(1));
                            }
                            System.out.println("点击单词"+sb.toString());
                            break;
                        }
                    }
                    break;
                }
                return false;
            }
        });



    /**
     * 反转字符串
     * @param s
     * @return
     */
    public String reverseStr(String s) {
        StringBuilder sb = new StringBuilder();
        for (int i = s.length() - 1; i >= 0; i--) {
            sb.append(s.charAt(i));
        }
        return sb.toString();
    }