Kuxi源码分析7 中文断行

 

textarea对于中文结尾(断行处刚好是中文)无法正常断行,要解决这个问题,必须了解textarea是如何断行的,实际上查看其代码知道,展示时是通过splitWords函数把文字全部解析为单词,每个单词作为一个text对象添加到frame中,由于单词按照空格间隔,所以无法断中文的"单词".原来TextArea的源码中分词函数如下:

 

	private void splitWords(String fullText, int style) {
		int beginIndex = 0;
		int endIndex = 0;
		String word;
		do {
			endIndex = fullText.indexOf(' ', beginIndex);
			if (endIndex == -1) {
				word = fullText.substring(beginIndex);
			} else {
				word = fullText.substring(beginIndex, endIndex);
			}
			if (word.length() != 0) {
				Text textWidget = new Text();
				textWidget.setText(word);
				if (style != Font.STYLE_PLAIN) {
					textWidget.setDefaultFontStyle(style);
				}
				add(textWidget);
			}
			beginIndex = endIndex + 1;
		} while (endIndex  != -1);
	}
 

Kuix的论坛上提供了下面的替换函数解决中文断行的问题.

 

    private void splitWords(String fullText, int style)
    {
        String str = fullText;//+" ";
        String word="";
        int len = str.length()-1;
        for (int i = 0; i <= len; i++) {
            char ch = str.charAt(i);
            if(i!=len)
                word = word + ch;
            if ((ch >= 48 && ch <= 57) || (ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))
                continue;
            if (word.length() != 0 || i==len) {
                Text textWidget = new Text();
                textWidget.setText(word);
                if (style != Font.STYLE_PLAIN) {
                    textWidget.setDefaultFontStyle(style);
                }
                add(textWidget);
                word = "";
            }
        }
    }
 

    应该说是做的很差的函数,对于数字,大小写26个英文子母外的其他字符都作为word的分隔符,这是相当有问题的,实际上应该把中文区间和空格作为分隔的基础,这个方法本身还有一个更大的缺陷,注意到原文的英文式分词是不把空格加进去的,也就是说Kuix默认会把每个text控件用一个空格的间隔分隔开了,所以替换为上述函数的结果就是显示中文虽然可以正常换行,但是每个中文之间都会有一个空格间隔着,看起来不美观,而且也很浪费空间.

    那么这个"隐藏"的空格是哪里来的,查TextArea的源代码,发现getGap的函数很有意思,不是继承Widget从样式中获取,而是直接获得空格的宽度,所以实际上TextArea容器中每个widget的间隔就是一个空格,修改getGap函数可以去掉空格:

 

	/* (non-Javadoc)
	 * @see org.kalmeo.kuix.widget.Widget#getGap()
	 */
	public Gap getGap() {
		if (cachedGap == null) {
//			cachedGap = new Gap(getFont().charWidth(' '), 0);
			cachedGap = new Gap(0, 0);
		}
		return cachedGap;
	}

    这样可以去掉中文之间的间隔,但是如果你试着去读取6,7页中文数据的话,立马就会报告Out of memory的错误,每个中文创建一个Text显然是相当浪费的,更完美的解决方案当然是自己断行.这里顺便说一下Kuix的标签和分行机制,首先看一下我的一个测试断行的分析描述:

 

 

1 无标签时支持<break/>
2 textarea不支持<break/>,不继承上一级容器的align属性,默认align是top,有中文时断行错误,出现只有很少文字的一行.
3 对英文断行也有缺陷,如果第一个单词就过长,会超出界限
4 多个空格也认为是1个空格,不支持回车,\n,<br>会保错
5 有意思的属性styled,default false,用途
Define if the text area use pseudo html style syntax. The value is a boolean (true or false).
假冒html样式?似乎是采用html的样式?整个reflow()函数都在为这个属性服务

     测试结果发现textarea似乎支持有限的html标签,实际上支持的html标签包括 img,i,b,strong,u,br,p,div等,也就是说对html标签的支持只包含字体,段落回车和图片。但是如果直接写在标签中都必须做转义才能使用,否则会报Unknow tag的错误,比如<br/>必须转义为&lt;br/&gt;还有另外一种形式可以不用转义,此时可以直接写入html标签和<break/>,如下:

<textarea style="align:top-left"><![CDATA[test<br>new line]]></textarea>

    这个是题外话,需要进一步了解请自行看TextArea.reflow和LightXmlParser的代码,注意到reflow大多数的代码其实都是解析和实现简单的html标签。

    Kuix断行实际上是依靠text来实现的,textarea只不过保证英文单词不被拆分在不同的行,而且猜测默认都是采用flowlayout来实行布局。要实现软回车,必须自己加上Kuix的标准标签<break></break>.而这个标签上面说过,在textarea的内容中也是不支持的.那么要实现中文断行,而且效果较好的话,就只能自己根据屏幕大小和字体断行,另外TextArea还有一个问题就是本身不支持textfield的编辑功能,这也是一个相当大的缺陷,作者说是因为两者展示时采用的方法不同,要实现它的编辑功能,必须另外弹出一个窗口进行编辑,具体方法不再提供,这里只分析Kuix的断行的处理方式,大家可以从网上另外找寻中文断行的代码参考.

    修改后的textarea效果如下:
    讨论了那么多,实际上还引申了一个问题,Kuix的断行依据,Kuix的布局方式是相当特殊的,我想这也是它不支持横向滚动条的原因,虽然widget有width属性,但是无论样式和属性中,实际都上没有对width数值的设置,反而是有一个min-size的允许设置最小的尺寸,当控件内容超多最小尺寸时,控件会自动伸展,也就是说实际上widget是没有固定大小的,系统在doLayout时再去计算实际大小,这实际上导致了一个问题,当控件的内容(如textfield的文字)发生变化是,widget会自增长,甚至超出屏幕的宽度.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值