How to prevent EditText from breaking a line after punctuation - android

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.

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.

This Line Breaking algorithm in Android really sucks, it isn't even logically correct - a comma can not be the last character of a line. it only produces unnecessary line breaks, which results in extremely weird text layout.

Hi Here is one method I first get from another guy and then make a little bit changes, it really works for me you can have a try.
//half ASCII transfer to full ASCII
public static String ToSBC(String input) {
char[] c = input.toCharArray();
for (int i = 0; i< c.length; i++) {
if (c[i] == 32) {
c[i] = (char) 12288;
continue;
}
if (c[i]<=47 && c[i]>32 )
c[i] = (char) (c[i] + 65248);
}
return new String(c);
}
}
here it is. I change some special characters from half corner to full corner, such as "," ".", and the effect is pretty good. You can have try.

Related

How to understand the view hierarchy dumped by "adb shell dumpsys activity"? [duplicate]

I'm logging views out to the logcat to distinguish between different views for debug purposes.
What I've noticed is that the output (caused essentially by View.toString) is something like this:
com.example.app.CustomView{7b14550 IFE...C.. ........ 0,0-1440,315}
What does each section between the curly brackets mean?
UPDATE: Just thought the answer may be in the View source code and had a look. For anyone looking to know this there is a toString() method that explains each of the values.
When you call .toString() to any given class, unless it is overridden, it will call toString() as it's defined in in Object. Every class has Object as a root in some or another way. If you extend one class, that class' superclass is Object. If the class extended extends a different class, that class' superclass is Object. You get the idea here. So from the Object documentation:
/**
* Returns a string representation of the object. In general, the
* {#code toString} method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
* <p>
* The {#code toString} method for class {#code Object}
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `{#code #}', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* <blockquote>
* <pre>
* getClass().getName() + '#' + Integer.toHexString(hashCode())
* </pre></blockquote>
*
* #return a string representation of the object.
*/
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
Meaning unless you override it, it prints out that. Meaning it prints out the hex string of the class' hash code.
So unless it is overridden to print out something else, it prints out the hex string of the class' hashcode.
But in case of the View class, this is the method it has:
public String toString() {
StringBuilder out = new StringBuilder(128);
out.append(getClass().getName());
out.append('{');
out.append(Integer.toHexString(System.identityHashCode(this)));
out.append(' ');
switch (mViewFlags&VISIBILITY_MASK) {
case VISIBLE: out.append('V'); break;
case INVISIBLE: out.append('I'); break;
case GONE: out.append('G'); break;
default: out.append('.'); break;
}
out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.');
out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.');
out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D');
out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.');
out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.');
out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.');
out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.');
out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.');
out.append(' ');
out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.');
out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.');
out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.');
if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) {
out.append('p');
} else {
out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.');
}
out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.');
out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.');
out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.');
out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.');
out.append(' ');
out.append(mLeft);
out.append(',');
out.append(mTop);
out.append('-');
out.append(mRight);
out.append(',');
out.append(mBottom);
final int id = getId();
if (id != NO_ID) {
out.append(" #");
out.append(Integer.toHexString(id));
final Resources r = mResources;
if (id > 0 && Resources.resourceHasPackage(id) && r != null) {
try {
String pkgname;
switch (id&0xff000000) {
case 0x7f000000:
pkgname="app";
break;
case 0x01000000:
pkgname="android";
break;
default:
pkgname = r.getResourcePackageName(id);
break;
}
String typename = r.getResourceTypeName(id);
String entryname = r.getResourceEntryName(id);
out.append(" ");
out.append(pkgname);
out.append(":");
out.append(typename);
out.append("/");
out.append(entryname);
} catch (Resources.NotFoundException e) {
}
}
}
out.append("}");
return out.toString();
}
And what is printed out means:
7b14550 - hash code identifying the view. Note that this will NOT remain constant, as it after all is a hash.
I - the view is invisible
F - the view is focusable
E - the view is enabled
C - the view is clickable
0,0-1440,315 - indicates left, top, right and bottom offset.
But as you see from the code above, there are many different keys to be aware of.
And the brackets are there to guide you as to what of the details that are printed out is connected to the View you have called .toString on. As far as I have understood, they have no function outside showing you what of the text printed out belongs to that class.
You can override toString and make it print out whatever data you want: fields, results of methods, or just do nothing
Tips for the future
Next time you wonder what a method does (assuming you use an IDE), CTRL+Left click on the method/field in question. If you use another program, as long as you're running semantic autocomplete backed by a supported LSP, there should still be a way to open the target function. Look up what applies for your editor.
Either way, this opens the target class and shows you the method source and any potential documentation left by the developer(s).
Reading the source code I can tell you that
7b14550 is a hash code that identifies the View
I = view is invisible
F = view is focusable
E = view is enabled
C = view is clickable
0,0-1440,315 indicates left, top, right and bottom offset in the screen.

How do i check the length for Color.red(c) in android?

As for the RGB value maximum value for each can be 255(length is 3) but for each color. For eg : if Color.red(c) gives the value 12(length is 2) for red then i want to add 0 in front and make it 012 how can i do that. It was possible if i could check the length but i do not know how to do it.
To check the length you can try something like
int red = Color.red(c);
if (red < 10) {
//0...9
} else if (red < 100) {
//10..99
} else {
//100..255
}
In the each if you can add to the value as many zeros as you want.
String colorLeadingZeroes = String.format("%03d", Color.red(c));
this will force the result to be a string of three digits with leading zeros replacing the spaces

Android: Converting a set of functions into an equation

I am 99% sure that this cannot be done, however I thought I would ask to be certain.
I am attempting to create an application that calculates the required dice roll for an action in a popular tabletop war game.
The following is this calculation in Java
int x = ((WSattacker * 2) - WSdefender);
int y = (WSattacker - WSdefender);
String result;
// Calculation for a +5
if (x <= -1) {
result = "5+";
}
// Calculation for a +4
else if (x >= 0 && y <= 0) {
result = "4+";
}
// Calculation for a +3
else if (y > 0) {
result = "3+";
} else {
result = "Error";
}
return result;
Now my issue is that to avoid copywriter infringement I cannot mention the name of the game in my application, and probably cannot hard code the above calculation in the app.
This means that it is difficult to tell a potential user what the app will do.
The only solution I can think of is to make the application generic and allow the user to input the calculation required in the form of an equation.
An equation that I can place anonymously on a public board or similar.
Therefore my questions are as follows.
Is there another way of going about this?
If no, is it possible to condense the above code into a single expression/ equationi.e. one that removes the if and else statements
To answer question 2:
result = test_condition_1 ? result2_if_true : (test_condition_2 ? result2_if_true : test3_or_result2);
You can then build up 'compound' test conditions this way, and it's based upon ternary operators.
EDIT
Ternary operators are a short-hand way of writing if..then..else statments, and more information can be found in the wiki-link above. An example of its use is below, which you can compile and run:
public class TernaryTest {
public static void main(String [] args){
int x = 14;
int y = 5;
String result = ( x <= 10 ) ? "Less than 10" : "More than 10";
System.out.println("Result is: " + result);
}
}
Try running it and see the result as you change the value of x to understand how it works. Then it's possible to extend it to include and else by replacing the "more than 10" string.

HTML Formatted String inserting into TextViews and EditText

All,
I have a database that will store an HTML tagged text to retain formatting information from an EditText. I create this string using HTML.toHtml(EditText.getText). I notice this method wraps whatever Spanned Text is put in it with <p> and </p>. The issue with that is when I got to use the method HTML.fromHtml(HTMLFormattedString) and then use the setText method of either a TextView or EditText there are two extra lines at the end of my actual text, which makes sense because that is how the paragraph tag works with HTML.
My question is is there anyway to make the textView or EditText shrink to not display the extra blank lines? What is the simplest way to do this? I have experimented with just removing the last <p> and </p>, but that only works if the user did not enter 3 or more new lines with the return key.
I ended up searching for white space at the end of the spanned text that was created and removed it. This took care of extra spaces due to the <p> </p> and was less time consuming than overriding the mentioned class to achieve the same results.
public SpannableStringBuilder trimTrailingWhitespace(
SpannableStringBuilder spannableString) {
if (spannableString == null)
return new SpannableStringBuilder("");
int i = spannableString.length();
// loop back to the first non-whitespace character
while (--i >= 0 && Character.isWhitespace(spannableString.charAt(i))) {
}
return new SpannableStringBuilder(spannableString.subSequence(0, i + 1));
}
Well this is just a round about approach. I had the same issue. And you are provided with two options,
1)As you said that paragraph tag works the way what you have suspected. What it does , it appends two "\n" values to the end of each <\p> tag. So you can convert the html to string and remove the last two characters which are usually two "\n"s
or
2) You have get into the Html Class itself. That is, you have to override the HTML class and look for handleP(SpannableStringBuilder text) and change its core logic a little bit.
private static void handleP(SpannableStringBuilder text) {
int len = text.length();
if (len >= 1 && text.charAt(len - 1) == '\n') {
if (len >= 2 && text.charAt(len - 2) == '\n') {
return;
}
text.append("\n");
return;
}
if (len != 0) {
text.append("\n\n");
}
}
As you can see here, it appends two "\n" in len!=0 which is were you have to do the change.

How to Delegate Control from a String to a series of functions in C

This is a performance critical part of my android application, and I am using the NDK (c) to process a large bitmap array.
int blender(const char* blendMode, int c1, int c2, int amount){
int sob, sog, sor, soa, dsr, dsg, dsb, dsa = 0;
dsr = Argb_GetRed(c1);
dsg = Argb_GetGreen(c1);
dsb = Argb_GetBlue(c1);
dsa = Argb_GetAlpha(c1);
sor = Argb_GetRed(c2);
sog = Argb_GetGreen(c2);
sob = Argb_GetBlue(c2);
soa = Argb_GetAlpha(c2);
int src_alpha, mix_alpha, dst_alpha;
src_alpha = soa * ((255 * amount) / 100) >> 8;
if (!strcmp(blendMode, "normal")) {
PSD_BLEND_NORMAL(dsr, sor, mix_alpha);
PSD_BLEND_NORMAL(dsg, sog, mix_alpha);
PSD_BLEND_NORMAL(dsb, sob, mix_alpha);
}
else if (!strcmp(blendMode, "exclusion")) {
mix_alpha = soa / 255;
//.... it's not always just the 3 macros
PSD_BLEND_EXCLUSION(dsr, sor, mix_alpha);
PSD_BLEND_EXCLUSION(dsg, sog, mix_alpha);
PSD_BLEND_EXCLUSION(dsb, sob, mix_alpha);
}
~~~~~~~~~ X 20 or so blend modes ~~~~~~~~~~~~
}
Currently it's running this blender function on every pixel, and doing a switch (clearly inefficient)
also, it has to take the original command as a string (From json, and passed down through java)
I can think of a couple ways to make it more efficient, but they all involve writing 2 giant switch statements. I would prefer to use 1 switch statement, or lookup if possible
Thank you!
Pretty nasty problem but I got a "hackish" idea.
If the 'blendMode' names are chosen nicely, you could compare only the first two (or three) letters of the strings. If there are multiple strings with same first letters, you could make a special case and compare first and third letter and so on.
This trick would make the code a lot faster than calling strcmp() all the time. Also inlining the compare function might help too.
Here is some code:
/* compares first two letters of the string */
inline int fast_cmp(const char *mode, const char *cmp) {
return (mode[0] == cmp[0] && mode[1] == cmp[1]) ? 1 : 0;
}
if( fast_cmp(blendMode, "no") ); /* for "normal" */
if( fast_cmp(blendMode, "ex") ); /* for "exclusion" */
In action: http://ideone.com/OiXS0
Ofcourse the comparisons could be written directly into if / else statements but it might get confusing. This can be fixed with small and nifty macro:
#define FAST_CMP(x, y) x[0] == y[0] && x[1] == y[1]
And here is the macro in action: http://ideone.com/NQFwW
This macro version is perhaps the fastest way to do the comparison.

Categories

Resources