系统自带的控件TextView有时候没满一行就换行了,为了解决这个问题,自定义了一个TextView,只有一行显示不完全的情况下才会去换行显示,代码如下:

package com.open.textview;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View; /**
* 不换行的TextView
* @author Administrator
*
*/
public class CusTextView extends View { protected float textSize=35;
protected float paddingLeft=0;
protected float paddingRight=0;
protected float paddingTop=0;
protected float paddingBottom=0; protected float lineSpace=5;
protected int lineWidth=320;
protected float lineHeight=20;
protected int lineCount;
protected int maxLines=-1;//最大的行数 protected String mText;
protected ArrayList<LineParams> lineList=new ArrayList<LineParams>(0);//行的字符串索引 protected Paint mPaint = new Paint();
{
mPaint.setTextSize(textSize);
mPaint.setAntiAlias(true);
} public CusTextView(Context context) {
super(context);
} public CusTextView(Context context, AttributeSet attrs) {
super(context, attrs);
} public CusTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public void setText(String text) {
this.mText = text;
lineList.clear();
requestLayout();
invalidate();
} public void setText(String text,int maxLines)
{
this.maxLines=maxLines;
this.setText(text);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if(TextUtils.isEmpty(mText))
{
setMeasuredDimension(0, 0);
return;
} lineWidth=(int)(MeasureSpec.getSize(widthMeasureSpec)-paddingLeft-paddingRight);//每行的宽度
Rect bounds = new Rect();
mPaint.getTextBounds(mText, 0, mText.length(), bounds);
lineHeight=bounds.bottom-bounds.top; maxLines=-1;
lineList.clear();
calculate();
lineCount=lineList.size();//总行数
maxLines=(maxLines>0)?Math.min(lineCount, maxLines):lineCount; int measuredHeight=0;//总的高度
if(maxLines>0)
{
measuredHeight+=(paddingTop+paddingBottom);//顶部与底部
measuredHeight+=(maxLines-1)*lineSpace;//空隙的间隔
measuredHeight+=(maxLines*(lineHeight));//行高之和
} int result=measuredHeight;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = measuredHeight;
break;
case MeasureSpec.AT_MOST:
result = Math.min(measuredHeight, specSize);
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), result);
} @Override
protected void onDraw(Canvas canvas) { if(TextUtils.isEmpty(mText))
{
return;
} for(int i=0;i<lineList.size();i++)
{
if(i==0)
{
canvas.drawText(mText, lineList.get(i).startIndex, lineList.get(i).endIndex, paddingLeft, paddingTop+lineHeight, mPaint);
}
else
{
canvas.drawText(mText, lineList.get(i).startIndex, lineList.get(i).endIndex, paddingLeft, paddingTop+lineHeight+(lineHeight+lineSpace)*i, mPaint);
}
} } private void calculate()
{
int startIndex=0;
while(true)
{
int[] itemLine=getIndexArray(startIndex);
lineList.add(new LineParams(itemLine[0], itemLine[1]));
if(itemLine[1]>=mText.length())
{
break;
} startIndex=itemLine[1];
}
} private int[] getIndexArray(int startIndex)
{
int[] ret=new int[2]; int canholdcharSize=0;
int singleCharWidth=(int) mPaint.measureText(mText, startIndex, startIndex+1);//单个字符宽度
singleCharWidth=Math.max(singleCharWidth, 1);
canholdcharSize=lineWidth/singleCharWidth;//每行可以容纳的字数,非精确值 if(isOutOfIndex(startIndex,canholdcharSize))//检查是否越界了
{
canholdcharSize=mText.length()-startIndex;
} if(isFitness(startIndex,canholdcharSize,lineWidth))//如果linecharSize个字符还小于单行的长度,需要再次自加长度来判断
{
while(true)
{
canholdcharSize++;
if(isOutOfIndex(startIndex,canholdcharSize))
{
canholdcharSize--;
break;
} if(isFitness(startIndex,canholdcharSize,lineWidth))
{
continue;
}
else
{
canholdcharSize--;
break;
}
}
}
else //需要再次自减长度来判断
{
while(true)
{
canholdcharSize--;
if(isFitness(startIndex,canholdcharSize,lineWidth))
{
break;
}
else
{
continue;
}
}
} ret[0]=startIndex;
ret[1]=(startIndex+canholdcharSize);
return ret;
} private boolean isOutOfIndex(int startIndex,int linecharSize)
{
return startIndex+linecharSize>mText.length();
} private boolean isFitness(int startIndex,int canholdcharSize,int lineWidth)
{
return mPaint.measureText(mText, startIndex, startIndex+canholdcharSize)<=lineWidth;
} public class LineParams
{
public int startIndex;
public int endIndex; public LineParams(int startIndex, int endIndex)
{
this.startIndex = startIndex;
this.endIndex = endIndex;
} public boolean isInnerRange(int testNum)
{
return (testNum>=startIndex&&testNum<=endIndex);
} @Override
public String toString()
{
return "LineParams [startIndex=" + startIndex + ", endIndex="+ endIndex + "]";
}
}
}

Demo地址:http://download.csdn.net/detail/zz7zz7zz/6015937

邮箱:zz7zz7zz@163.com

微博:http://weibo.com/u/3209971935

[置顶] android 自定义TextView的更多相关文章

  1. [置顶] android 自定义ListView实现动画特效

    通过自定义ListView实现动画特效,被点击元素A向前移,A之前元素往后移动. 重点在于动画的实现: 具体代码如下: package com.open.widget; import java.uti ...

  2. [置顶] Android EditText/TextView使用SpannableString显示复合文本

    在Android中EditText用于编辑文本,TextView用于显示文本,但是有时候我们需要对其中的文本进行样式等方面的设置.Android为我们提供了SpannableString类来对指定文本 ...

  3. [置顶] android 自定义圆角ImageView以及锯齿的处理

    看到很多人开发过程中要使用圆角图片时,解决方法有: 1.重新绘制一张图片 2.通过布局来配置 3.通过重写View来实现 其中1,2在这里就不讲了,重点讲讲方法三的实现. 实现一:通过截取画布一个圆形 ...

  4. [置顶] Android RadioButton与TextView浪漫约会?

    情景一 今天主要实现一个国家与地区切换,就是当我们选中RadioButton时然后将值设置到TextView中,听着这需求应该不难对吧?那么我们就开始约会吧? 看下原型图 准备条件: 首先需要一个ra ...

  5. [置顶] Android开发笔记(成长轨迹)

    分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API ...

  6. [置顶] Android布局管理器 - 详细解析布局实现

    布局管理器都是以ViewGroup为基类派生出来的; 使用布局管理器可以适配不同手机屏幕的分辨率,尺寸大小; 布局管理器之间的继承关系 : 在上面的UML图中可以看出, 绝对布局 帧布局 网格布局 相 ...

  7. Android 自定义TextView 实现文本间距

    Android系统中TextView默认显示中文时会比较紧凑,不是很美观.为了让每行保持一定的行间距,可以设置属性android:lineSpacingExtra或android:lineSpacin ...

  8. [置顶] android开发之来电自动拒接并自动回复短信_上课模式app

    上课的时候老师说总是错过电话,对方打来没人接还一遍遍的打,觉得可以有个app在上课期间自动拒接电话,并自动回复短信过去. 当然了,需要权限的. 尝试做了个雏形出来. 界面如下: 主要代码如下: pac ...

  9. [置顶] Android事件—单选按键和下拉按键

    在平常的开发中单选按键和下拉按键是非常常用的2个点击事件.首先介绍下单选按键 1:单选按键,单选的主键是radiogroup 这个主键也是很重要的 首先介绍下主键的布局 <?xml versio ...

随机推荐

  1. WebSphere优化

    优化WebSphere WebSphere里的profile刚配完,一般默认的heapsize即Xms与Xmx值只有256mb,而IBM WAS是几个J2EE服务器中最吃内存的机器,在布署一些EAR应 ...

  2. 基本的编程原则SOLID

    1.单一职责原则:每个类只负责完成一个职责,当它需要完成多个职责时就需要将它拆分开来. 2.开放封闭原则:对扩展开放,对修改封闭. 3.里氏替换原则:子类对象可以替换(代替)它的所有父类(超类)对象. ...

  3. Laravel 5.1 ACL权限控制 一

    请自行添加命名空间,代码下载地址 https://github.com/caoxt/learngit 1.所需要用到的数据表 users(用户表).roles(角色表).role_user(用户角色对 ...

  4. 转:触屏中的js事件

    一.触摸事件 ontouchstartontouchmoveontouchendontouchcancel 目前移动端浏览器均支持这4个触摸事件,包括IE.由于触屏也支持MouseEvent,因此他们 ...

  5. VC++中的头文件包含问题

    在一些大的工程中,可能会包含几十个基础类,免不了之间会互相引用(不满足继承关系,而是组合关系).也就是需要互相声明.好了,这时候会带来一些混乱.如果处理得不好,会搞得一团糟,根据我的经验,简单谈谈自已 ...

  6. Objective-C中的类目(Category),延展(Extension)

    类目和延展的作用都是为了扩展一个类. Objective-C中的类目(Category) 一.类目的定义和作用 类目也叫分类,英文Category,在没有原类.m文件的基础上,给该类添加方法. 比如, ...

  7. Cocos2d-x 创建自己定义项目模板

    你是否以前为cocos方便高速开发而兴奋,你是否以前为各种工具的便利开发而感动,但如今的你是否为每次创建一个新的项目都是HelloWorldScene而苦恼? 好吧,事实上我也感觉到了,每次创建一个项 ...

  8. Codeforces 455B A Lot of Games(字典树+博弈)

    题目连接: Codeforces 455B A Lot of Games 题目大意:给定n.表示字符串集合. 给定k,表示进行了k次游戏,然后是n个字符串.每局開始.字符串为空串,然后两人轮流在末尾追 ...

  9. iOS开发中两个不错的宏定义

    /** Synthsize a weak or strong reference. Example: @weakify(self) [self doSomething^{ @strongify(sel ...

  10. Minimum Window Substring @LeetCode

    不好做的一道题,发现String Algorithm可以出很多很难的题,特别是多指针,DP,数学推导的题.参考了许多资料: http://leetcode.com/2010/11/finding-mi ...