Android EditText 换行和对齐问题研究

1.原生方法
换行
Android textview换行属性有BreakStrategy和hyphenationFrequency
android:breakStrategy
Break strategy (control over paragraph layout).
Must be one of the following constant values.
ConstantValueDescription
balanced2Line breaking strategy balances line lengths.
high_quality1Line breaking uses high-quality strategy, including hyphenation.
simple0Line breaking uses simple strategy.
对于TextView默认值是high_quality,对于EditText默认值是simple

连字符
android:hyphenationFrequency
Frequency of automatic hyphenation.
Must be one of the following constant values.
ConstantValueDescription
full2 
none0Standard amount of hyphenation, useful for running text and for screens with limited space for text.
normal1Less frequent hyphenation, useful for informal use cases, such as chat messages.
当breakStrategy的值不是simple时改策略的normal和full有效。
这两个属性是Android6.0引入的,实现在frameworks/minikin/libs/minikin目录下,java通过jni调用so库。但是按照icu的规范, 英文单词是尽可能的不中断的 ,标点符号不会在行尾或者行首,所以即使设置high_quality和full的值,视觉上看起来也没啥大变化。

对齐
android:justificationMode
有两个值,
JUSTIFICATION_MODE_INTER_WORD
added in API level 26
int JUSTIFICATION_MODE_INTER_WORD
Value for justification mode indicating the text is justified by stretching word spacing.

Constant Value: 1 (0x00000001)
JUSTIFICATION_MODE_NONE
added in API level 26
int JUSTIFICATION_MODE_NONE
Value for justification mode indicating no justification.

Constant Value: 0 (0x00000000)
一个是不启用,另一个是启用
原理就是设置Paint的setWordSpacing方法调整单词的间距填满整行
/**
 * Set the paint's word-spacing for text. The default value is 0.
 * The value is in pixels (note the units are not the same as for
 * letter-spacing).
 *
 * @param wordSpacing set the paint's word-spacing for drawing text.
 * @hide
  */
public void setWordSpacing( float wordSpacing) {
    nSetWordSpacing ( mNativePaint , wordSpacing);
}
这个也是网上大部分justify textview开源项目的思路,具体代码可见android.text.Layout的代码
注意的是这个属性不仅是Android8.0才引入的,而且对于EditText来说是无效的,因为EditText和TextView使用的是不同的Layout,EditText使用的是DynamicLayout,而TextView使用的是StaticLayout,当然可以通过反射的方式强制EditText开启justify模式,但是据我试验在引入斜体等会导致字体宽度变化的因素情况下layout会出现奇怪的现象,例如设置完justify模式后设置部分内容为斜体,layout会马上混乱。

2.其他方法
1.justify
我在网上找到的大部分方法都是justify的思路,例如
都要override OnDraw,通过调整间距使布局整齐。但是这种方法忽视了TextView中的其它逻辑,Android源码中的TextView一个文件就有8000+行代码,android.text包下的文件基本都是为TextView服务的,对于文本不变的TextVIew来说还可行,对于EditText来说行不通。

2.更改源码
有更改源码的能力的话,例如手机厂商,更改StaticLayout的代码即可。

3.反射的方式改源码
textview和android.text包下的hide类和方法非常多,从4.x到8.0变化也很多,例如linebreak的方法在5.0之前是java代码,之后就是jni了,而且jni的方法也一直在变,StaticLayout初期还是通过new来创建实例,后来就新加了Builder静态内部类,反射方式修改个人觉得不大可行。

4.把TextView源码整个挪动到app来
这个方法我试验过了,挪动的是4.4的代码,因为这个版本line break的逻辑在java代码中(比较好改),但是hide类和方法太多了,通过反射和删除的方式代码能编译调通,line break效果也有,但是可想而知的是bug会很多的。

4.4版本删除代码在StaticLayout.java

                        // From the Unicode Line Breaking Algorithm (at least approximately)
                        //delete by lgy
//                        boolean isLineBreak = isSpaceOrTab ||
//                                // / is class SY and - is class HY, except when followed by a digit
//                                ((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
//                                (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
//                                // Ideographs are class ID: breakpoints when adjacent, except for NS
//                                // (non-starters), which can be broken after but not before
//                                (c >= CHAR_FIRST_CJK && isIdeographic(c, true) &&
//                                j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false));
//
//                        if (isLineBreak) {
//                            okWidth = w;
//                            ok = j + 1;
//
//                            if (fitTop < okTop)
//                                okTop = fitTop;
//                            if (fitAscent < okAscent)
//                                okAscent = fitAscent;
//                            if (fitDescent > okDescent)
//                                okDescent = fitDescent;
//                            if (fitBottom > okBottom)
//                                okBottom = fitBottom;
//                        }
最致命的是framework源码中不少地方是指定了类的,例如Span中有参数会指定是android.text.Layout,挪过来的Layout是无法使用的。输入法有相关参数是指定android.text.TextView的,挪过来的TextView它也不认啊。
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值