在做某些应用时,我们通常需要处理显示大量的文字,例如,要实现一个电子书阅读器,需要处理的文字非常多,这时我们应该会需要一系列的文本控件,比如:菜单,列表、文本显示等,这里我们主要分析实现一个用于文本显示的控件,他需要提供自动换行,翻页等功能,在网上看到很多人在询问如何实现这样的控件,并且网上提供的大多数是自动换行,没有实现翻页,并且实现的效率也不是很高,所以这里我们再次通过一个简单的算法来实现这样一个功能。
实现之前,我们首先需要分析该控件的功能,首先,需要显示任意数量的文本,需要对文本实现自动换行,翻页等功能。我们都知道在做JavaME应用程序时,程序员通常不能指定文字的大小等,因为文字的大小一般会根据不同的手机而不同,因此我们需要动态计算字体的大小,文本的长度等。
下面首先构建一个类StringLayout来实现对字符串的布局,主要包括一下一些成员变量:
public class StringLayout {
public int layoutWidth, layoutHeight, layoutX, layoutY;
private int lineGap; //行高
private String text; //要处理的文本
private int fontHeight; //字体的高度
private int lineCount; //行数
private Vector line; //存放拆分之后的字符串
private Font font =Font.getDefaultFont();//Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN,Font.SIZE_SMALL); //字体
private int currLine = 0; //当前行
public boolean isChange = false;
private int rgbcolor=0xffffff; //颜色
public StringLayout() {}
//省略部分...
}
首先考虑实现自动换行,要自动换行,就需要先需要对要处理的文本进行截取,截取的过程需要根据指定的文本显示区域来定,下面我们通过init函数来对字符串进行截取,代码如下:
/**
* 构造函数
* Str:布局中的字符串
* LayoutX:布局顶点X
* LayoutY:布局顶点Y
* LayoutWidth:布局宽度
* LayoutHeight:布局高度
* Gap:各行之间的空隙
*/
public void init(String Str, int LayoutX, int LayoutY, int LayoutWidth,
int LayoutHeight, int Gap) {
//如果不加上最后一个字符则最后一个字符不会被截取
text = Str+Str.charAt(Str.length() - 1);
layoutX = LayoutX;
layoutY = LayoutY;
layoutWidth = LayoutWidth;
layoutHeight = LayoutHeight;
lineGap = Gap;
int begin = 0;
fontHeight = font.getHeight();
lineCount = 0;
line = new Vector(5, 2);
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if (font.stringWidth(text.substring(begin, i + 1)) >= layoutWidth
|| i == text.length() - 1 || ch == '\n') {
line.addElement(text.substring(begin, i));
if (ch == '\n')
begin = i + 1;
else
begin = i;
lineCount++;
}
}
}
截取的原理为截取一段字符串,然后比较该字符串的宽度是否超过了指定的文本显示区域的宽度,截取的索引为“i+1”,如果超出范围则将索引为“i”之前的字符串取出存放到一个准备好的Vector中,并且行数lineCount也随之加一,再进入下一个循环继续截取,当然如果遇到“\n”这样的换行符则直接换行,当然还有其他的一些自定义的换行符。该函数的第一行中,我们对每个字符串加上了一个他的最后一个字符,原因则是我们截取的长度索引都是“i+1”,因此避免最后一个字符丢失,因此在开始时就多加上了最后一个字符。现在所有的文本都按照指定的文本区域截取并存放到Vector中了。下面就需要开始绘制这些字符段了。绘制代码如下:
public void draw(Graphics g) {
if(text==null)return;
int i1 = g.getClipX();
int j1 = g.getClipY();
int k1 = g.getClipWidth();
int l1 = g.getClipHeight();
g.setColor(rgbcolor);
g.setClip(layoutX, layoutY, layoutWidth, layoutHeight);
g.setFont(font);
for (int i = currLine; i < line.size(); i++) {
String s = (String) line.elementAt(i);
g.drawString(s, layoutX, layoutY + (i - currLine) * (fontHeight + lineGap), 0);
}
g.setClip(i1, j1, k1, l1);
isChange = false;
}
绘制过程,则非常简单,通过循环绘制Vector中的元素即可,并且需要先通过setClip设置好裁剪区域,循环需要从当前行数currLine开始,这样就有利于我们实现翻页操作。
下面,我们通过一段文字来测试该控件的使用,截取的字符串是否正确,代码如下:
mStringLayout =
new StringLayout();
String string = "自动换行
\n翻页,测试自\n动换行,翻页,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,自动换行\n翻页,测试自\n动换行,翻页,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ自动换行\n翻页,测试自\n动换行,翻页,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
mStringLayout.init(
string+string+string+string+string+string, 0, 0, 240, 320, 3);
在paint()函数中调用mStringLayout.draw(g);即可,绘制效果如图2-1所示。
如果需要加入翻页,则在StringLayout类中加入如下几个方法即可,分别为检测是否能够翻页,和执行翻页。
public boolean isNext() {
if (currLine < lineCount - 1)
return true;
else
return false;
}
public void next() {
if (currLine < lineCount - 1) {
currLine++;
isChange = true;
}
}
public boolean isPrev() {
if (currLine > 0)
return true;
else
return false;
}
public void prev() {
if (currLine > 0) {
currLine--;
isChange = true;
}
}
当然了,使用也就很简单了,只需要在按键或者触摸函数中调用该控件的翻页函数即可。另外,该类还可以进行一些其他的扩展,比如设置字体的颜色setColor和字体setFont等,由于篇幅关系,我们就不一一贴出代码了,大家可以自行任意扩展。该类是通过低级界面实现了,因此,可以很容易用于游戏开发中的文字布局显示。