Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent EditText from breaking a line after punctuation

As default, an Android EditText will break a line if the line is longer than the view, like this:

Thisisalineanditisveryverylongs (end of view)
othisisanotherline

or if the line contains a punctuation character, like this:

Thisisalineanditsnotsolong;     (several characters from the end of view)
butthisisanotherline

As a requirement of my work, the text has to break a line only if the line is longer than the view, like this:

Thisisalineanditsnotsolong;andt (end of view)
hisisanotherline

There must be a way to achieve this, am I right? So far I haven't found anyway to do this.

like image 428
hoangbv15 Avatar asked Feb 24 '23 02:02

hoangbv15


1 Answers

The way TextView (and EditText) breaks the text is through private function calls to BoringLayout internally. So, the best way would be to sublcass EditText and rewrite these functions. But it will not be a trivial task.

So, in the TextView class there are creations of different classes for text style. The one we look is DynamicLayout. In this class we reach to a reference of the class StaticLayout (in a variable called reflowed). In the constructor of this class you will find the text wrap algorithm:

/*
* From the Unicode Line Breaking Algorithm:
* (at least approximately)
*  
* .,:; are class IS: breakpoints
*      except when adjacent to digits
* /    is class SY: a breakpoint
*      except when followed by a digit.
* -    is class HY: a breakpoint
*      except when followed by a digit.
*
* Ideographs are class ID: breakpoints when adjacent,
* except for NS (non-starters), which can be broken
* after but not before.
*/

if (c == ' ' || c == '\t' ||
((c == '.'  || c == ',' || c == ':' || c == ';') &&
(j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&
(j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
((c == '/' || c == '-') &&
(j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
(c >= FIRST_CJK && isIdeographic(c, true) &&
j + 1 < next && isIdeographic(chs[j + 1 - start], false))) {
okwidth = w;
ok = j + 1;

Here's where all the wrapping goes. So you will need to subclass take care for StaticLayout, DynamicLayout, TextView and finally EditText which - I am sure - will be a nightmare :( I am not even sure how all the flow goes. If you want - take a look at TextView first and check for getLinesCount calls - this will be the starting point.

like image 95
Kamen Avatar answered Apr 06 '23 03:04

Kamen