您的位置:首页 > 移动开发 > Android开发

Android-TextView换行排版混乱-允许设置SpannableString

2016-01-14 15:10 1796 查看
首先感谢两个网站提供的灵感:

http://www.it165.net/pro/html/201405/14606.html

另一个忘了地址了,哪天找出来加上

1.概述

TextView在换行时遇到首字符为字母、符号、汉字等时会产生提前换行、排版混乱等,看图

带ta看房处”,当第一个有字母开头时,提前换行



2.解决方案:1).半圆角转换 2).字符过滤成全英文字符

3).前两种解决都不够理想——自定义TextView才是王道

3.分析自定义步骤:

1).文字大小统一时,每当每行排满进行换行,然后绘制每行的内容

2).SpannableString设置了RelativeSizeSpan、ForegroundSpan等,甚至设置了多个,

需要逐字绘制,并在排满时进行换行

效果图:


前两个橙色背景是正常textview,黄色背景是自定义的效果

解决了允许以字母为首且不会提前换行的情况

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

paint = new Paint();
/*
设置宽度
*/
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
//父控件允许子控件的最大宽度,包括子控件设置的具体值或者fill_parent
if(specMode == MeasureSpec.EXACTLY) { //fill_parent,也相当于设置了exactly
mWidth = specSize;
} else {
//子控件需要的宽度
int desiredSize = (int) (getPaddingLeft() + getPaddingRight() + mContent.length() * getTextSize());
if(specMode == MeasureSpec.AT_MOST) { //wrap_content
//两者取最小
desiredSize = Math.min(specSize, desiredSize);
}
mWidth = desiredSize; //TextView的宽度
}

//        /*
//        根据文本内容设置高度
//         */
//        Rect textBound = new Rect();
//        paint.setTextSize(getTextSize());
//        paint.getTextBounds(mContent,0,mContent.length(),textBound);
//        mHeight = textBound.height() + getPaddingBottom() + getPaddingTop();

mContentWidth = mWidth - getPaddingLeft() - getPaddingRight(); //View里面内容的宽度
setMeasuredDimension(mWidth, heightMeasureSpec);
}

public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}


重写setText(Charsequence text, BufferType type) 方法,并获取SpannableString设置

@Override
public void setText(CharSequence text, BufferType type) {
//该行不能删掉,否则出错
super.setText("", type);
if(text instanceof SpannableString) {
SpannableString sStr = (SpannableString) text;
//获取所有的ForegroundSpan
ForegroundColorSpan[] spans =  sStr.getSpans(0, sStr.length(), ForegroundColorSpan.class);
for(ForegroundColorSpan span:spans) {
FGSpan fgSpan = new FGSpan();
fgSpan.fgColor = span.getForegroundColor();
fgSpan.start = sStr.getSpanStart(span);
fgSpan.end = sStr.getSpanEnd(span);
fgSpans.add(fgSpan);
}
//获取所有的RelativeSizeSpan
RelativeSizeSpan[] spans2 = sStr.getSpans(0, sStr.length(), RelativeSizeSpan.class);
for(RelativeSizeSpan span:spans2) {
RLSpan rlSpan = new RLSpan();
rlSpan.propertion = span.getSizeChange();
rlSpan.start = sStr.getSpanStart(span);
rlSpan.end = sStr.getSpanEnd(span);
rlSpans.add(rlSpan);
}
}
//内容赋值
mContent = text.toString(); //如果mContent不是static的话,xml里面text无法同步
}


逐个字符绘制

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//逐个字符画出
int fgSpanIndex = 0; //标记fgSpans下标
int rlSpanIndex = 0; //标记rlSpans下标
paint.setColor(getCurrentTextColor());
paint.setTextSize(getTextSize());
float x = 0,y = 0; //绘制字符时的x,y坐标
Paint.FontMetrics fm = paint.getFontMetrics();
float baseLine = fm.descent - fm.ascent;
y = baseLine;
for(int i = 0; i < mContent.length(); i++) {
/*
画当前字符
*/
//处理RelativeSizeSpan——若当前字符有RelativeSizeSpan设置,则进行设置
if(rlSpans != null && rlSpans.size() > 0) {
if(rlSpanIndex < rlSpans.size()
&& i >= rlSpans.get(rlSpanIndex).start
&& i < rlSpans.get(rlSpanIndex).end) {
paint.setTextSize(rlSpans.get(rlSpanIndex).propertion*getTextSize());
} else if(rlSpanIndex < rlSpans.size() && i >= rlSpans.get(rlSpanIndex).end) {
rlSpanIndex++;
}
}
//处理ForegroundSpan——若当前字符有ForegroundSpan设置,则进行设置
if(fgSpans != null && fgSpans.size() > 0) {
if(fgSpanIndex < fgSpans.size()
&& i >= fgSpans.get(fgSpanIndex).start
&& i < fgSpans.get(fgSpanIndex).end) {
paint.setColor(fgSpans.get(fgSpanIndex).fgColor);
} else if(fgSpanIndex < fgSpans.size() && i >= fgSpans.get(fgSpanIndex).end) {
fgSpanIndex++;
}
}
if(i +2 <=mContent.length()/*主要是防止后面i+1,i+2越界*/
&& x >= mContentWidth - paint.measureText(mContent.substring(i+1,i+2))) { //换行
x = 0;
y += baseLine + fm.leading;
}
canvas.drawText(mContent.substring(i,i+1),x,y,paint);
//计算下个字符水平位置
x += paint.measureText(mContent.substring(i,i+1));
paint.setTextSize(getTextSize());
paint.setColor(getCurrentTextColor());
}
}


主Activity里面进行设置

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

MyTextView myTextView = (MyTextView) findViewById(R.id.my);
SpannableString sp1 = new SpannableString("是解决得快的健康减肥大力度dkfjkajdvb是解决得快的健康减肥大力度dkfjkajd是解决得快的健康减肥大力度dkfjkajd");
sp1.setSpan(new ForegroundColorSpan(getResources()
.getColor(R.color.blue)), 5,
10,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sp1.setSpan(new ForegroundColorSpan(getResources()
.getColor(R.color.red)), 5,
10,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sp1.setSpan(new RelativeSizeSpan((float) 2.0), 5,
7,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sp1.setSpan(new ForegroundColorSpan(getResources().
getColor(R.color.green_blue)),10,
15,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sp1.setSpan(new RelativeSizeSpan((float) 2.0), 10,
15,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
myTextView.setText(sp1);
}


此自定义的TextView不仅可以处理SpannableString属性,而且不用重新设置attr.xml文件,直接重写setText方法。

关于其它效果的设置,参考里面对SpannableString的处理,可以自行扩展,此处未进行高度设置,有简单方法的大牛等待共享

全部资源下载处:

http://download.csdn.net/detail/xiaoweiguoyuan/9404182
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: