自定义TextView解决文字排列不齐和自定义超链接

android提供的TextView控件可以自动换行,对于纯英文来说很好用,如果既有中文字符又有英文字符和特殊字符,全角字符和半角字符混在一块,就会出现经常一行没显示完就跳转到下一行显示了,文字排版参差不齐,超级难看,通过自定义TextView来实现我们需要的显示方式。

自定义MyTextView类代码如下:

package com.example.user.helloworld.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.user.helloworld.R;

/**
 * 解决textView 排版换行
 * @author 
 *
 */
public class MyTextView extends TextView {
    private String text;
    private float textSize;
    private float paddingLeft;
    private float paddingRight;
    private int textColor;
    private Paint paint1 = new Paint();
    private float textShowWidth;

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        text = this.getText().toString();
        textSize = this.getTextSize();
        textColor = getResources().getColor(R.color.accent);
        paddingLeft = this.getPaddingLeft();
        paddingRight = this.getPaddingRight();
        paint1.setTextSize(textSize);
        paint1.setColor(textColor);
        paint1.setAntiAlias(true);
    }

    /**
     * 设置画笔颜色
     * @param color
     */
    public void setPaintColor(int color){
        paint1.setColor(color);
    }
    @Override
    public void onDraw(Canvas canvas) {
        textShowWidth = this.getMeasuredWidth() - paddingLeft - paddingRight;
        int lineCount = 0;
        text = this.getText().toString();
        if (text == null)
            return;
        char[] textCharArray = text.toCharArray();
        float drawedWidth = 0;
        float charWidth;
        for (int i = 0; i < textCharArray.length; i++) {
            charWidth = paint1.measureText(textCharArray, i, 1);
            if (textCharArray[i] == '\n') {
                lineCount++;
                drawedWidth = 0;
                continue;
            }
            if (textShowWidth - drawedWidth < charWidth) {
                lineCount++;
                drawedWidth = 0;
            }
            canvas.drawText(textCharArray, i, 1, paddingLeft + drawedWidth,
                    (lineCount + 1) * textSize, paint1);
            drawedWidth += charWidth;
        }
    }
}
使用方法:在Activity类对应的布局文件main.xml中:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.helloworld.activity.MyTextViewActivity">
    <com.example.user.helloworld.view.MyTextView
        android:id="@+id/mtv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

在Activity类中:

MyTextView mTV_content = (MyTextView)findViewById(R.id.mtv_content);
調用mTV_content的setPaintColor可以设置文字颜色。

你可以觉得文字行间距太小,视觉上太紧凑了。可以通过修改onDraw方法中这一行

canvas.drawText(textCharArray, i, 1, paddingLeft + drawedWidth,
                    (lineCount + 1) * textSize, paint1);

改成:canvas.drawText(textCharArray, i, 1, paddingLeft + drawedWidth,(lineCount + 1) * textSize*1.2f, paint1);

我当时测试使用+6.0f的形式没有效果,使用*1.2f的方式有效果,至于为什么,我也不清楚。


TextView再学习(2016-11-24)

本期项目开发时,有这样的需求:1)能识别TextView中的手机号,使用蓝色标识出来; 2)点击手机号,出现弹窗显示手机号,点击手机号可拨打电话。

TextView文本中识别超链接(邮件地址、手机号和网址),最常用的是在TextView所在的布局文件中TextView节点添加属性android:autoLink="all",这样网

址、电话号码和邮件地址自动识别为超链接,这也是系统提供的。

但是系统提供的超链接包含下划线,超链接字体颜色,点击超链接文本的点击事件如何自定义呢?

我对这两天的学习进行总结,如下:

1)如果使用xml中autoLink方式设置超链接,可以去除超超链接下划线/超链接文本颜色。

xml中添加android:autoLink="phone"

public class UseSystemTextViewActivity extends Activity {

    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_use_system_text_view);
        mTextView = (TextView)findViewById(R.id.tvTelephone);
        String webLinkText = "我的手机号是18916961696" ;
        mTextView.setText(webLinkText);
        NoUnderlineSpan mNoUnderlineSpan = new NoUnderlineSpan();
        if (mTextView.getText() instanceof Spannable) {
            Spannable s = (Spannable) mTextView.getText();
            s.setSpan(mNoUnderlineSpan, 0, s.length(), Spanned.SPAN_MARK_MARK);
        }
        //设置超链接文本颜色
        mTextView.setLinkTextColor(getResources().getColor(R.color.red));
    }

    public static class NoUnderlineSpan extends UnderlineSpan {
        public NoUnderlineSpan() {}
        public NoUnderlineSpan(Parcel src) {}

        @Override
        public void updateDrawState(TextPaint ds) {
            super.updateDrawState(ds);
            ds.setUnderlineText(false);
        }
    }
}
通过这种方式可以去除超链接下划线,改文本颜色,但无法自定义点击超链接的点击事件。

通过自定义类继承ClickableSpan重写onClick和updateDrawState也不能达到效果。

2)那么如何自定义超链接点击事件呢?

 **需要自定义类继承ClickableSpan类,重写updateDrawState和onClick方法。onClick实现自定义点击事件,updateDrawState 实现字体颜色和下划线设置。

 **将SpannableString包装一个字符串,调用setSpan方法设置字符片段为ClickableSpan。

自定义类代码如下:

 private class NoLineClickSpan extends ClickableSpan {
        String text;
        public NoLineClickSpan(String text) {
            this.text = text;
        }
        @Override
        public void updateDrawState(TextPaint ds) {
            ds.setColor(ds.linkColor);
            ds.setUnderlineText(false); //去掉下划线
        }
        @Override
        public void onClick(View widget) {
            processHyperLinkClick(text); //点击超链接时调用
        }
    }

使用Spannable的setSpan设置超链接,代码如下:
String linkText = "TextView设置超链接文本颜色";
SpannableString spStr = new SpannableString(linkText);
ClickableSpan clickSpan = new NoLineClickSpan(spStr.toString()); //设置超链接
spStr.setSpan(clickSpan, 0, spStr.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.append(spStr);
mTextView.setMovementMethod(LinkMovementMethod.getInstance());
由此可见,如果想自定义点击事件,不能使用在xml中添加android:autoLink方式。
最后我参考这篇文章,Android Custom Hyperlinked TextView理解了怎么去实现,这篇写的非常好!!!

大概思路是:我们需要定义正则表达式,然后在字符串中找出所有匹配正则表达式的start,end和正则匹配的字符,全部保存起来(这里可以通过定义一个类T实现,使用ArrayList<T>保存),最后通过Spannable的setSpan设置点击事件。
代码学习:
 LinkEnabledTextView  (自定义的TextView)
 TextLinkClickListener 内部监听器
 ClickableSpan  - 负责点击事件
 gatherLinksForText() 一般在Activity中调用LinkEnabledTextView的gatherLinksForText方法,传入要识别超链接的字符串即可。

文字背景会出现淡蓝色的背景参考 http://www.mincoder.com/article/4466.shtml

有关SpannableStringBuilder SpannableString区别可以看看:
http://blog.csdn.net/harvic880925/article/details/38984705
http://qiita.com/sutchan/items/5153e6a21ad30dc9e3cd
对超链接各种实现方式总结的文章,也非常好!http://souly.cn/%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87/2016/01/29/TextView%E8%B6%85%E9%93%BE%E6%8E%A5%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%E6%80%BB%E7%BB%93/
3)我也试着在解决文字排版不整齐的MyTextView中去集成识别自定义正则匹配字符是超链接,实现自定义点击事件。由于MyTextView重写了onDraw方法,TextView设置LinkMovementMethod,LinkMovementMethod类的onTouchEvent于MyTextView的触屏事件存在冲突,出现了点击超链接事件不起作用。这个作为todo以后再研究吧!













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值