0%

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