I want to count the total number of characters a TextView can hold with 14dp text size and 100dp of width and with 100dp of height. then I have to add those characters' limits to an EditText.
<TextView
android:id="#+id/OFSO_text1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_weight="1"
android:layout_gravity="top|center"
android:fontFamily="#font/lato_bold"
android:gravity="center|bottom"
android:text="SEASONAL DISCOUNT ARE HERE"
android:textAlignment="center"
android:textAllCaps="true"
android:textColor="#color/lightcream"
android:textSize="14dp"
android:textStyle="normal"
android:autoSizeTextType="none"
/>
I have tried this code but this is not working properly. this provides me more char limit then this Textview can holds.
TextPaint paint = textView.getPaint();
int wordwidth=(int)paint.measureText("a",0,1);
int screenwidth = getResources().getDisplayMetrics().widthPixels;
int maxLength = screenwidth/wordwidth;
please help me out!! thanks in advance.
happy coding!!!
You are missing font size and typeface in your measurements.
// In case you are storing your font in res/font
Typeface typeface = ResourcesCompat.getFont(context, R.font.noto_sans_regular);
paint.setTypeface = typeface
paint.setTextSize = sizeOfYourFontInPixels
First of all, your textholder size varies from device to device,
And for the count, you can do something like,
int textLenght = yourtText.getText().toString().lenght();
if(textLenght>n) {
yourEditText.setText(yourText);}
Measuring Text: You can do something like this :
float textWidth = textView.getPaint().measureText(textView.getText().toString());
if(textView.getMeasureWidth() == n) {
Log.i("Text_count",textView.getText().toString().lenght());
}
or
if(textWidth == n) {
Log.i("Text_count",textView.getText().toString().lenght());
}
Try this
Add addTextChangedListener to the edittext for reading characters.
In override methods beforeTextChanged, onTextChanged and afterTextChanged, read characters like below
int length = etText.length();
int leftCharacters = 500 - length; //let default length of edittext is 500
Hope, it works for you!!
Related
I'm stuck on a strange little problem.
The goal with this activity is to display two texts, one is the original the second the answer text. The answer text contains errors and the user has to find and mark those errors.
The solution we came up with is to split the text into its words and display each word as its own in a TextView. All these TextViews are created dynamically at runtime, because there are many different texts to display.
There are two instances, where we need a 'line break': a) the text contains a linebreak () and b) the width of the display wouldn't fit any more text.
This solution works most of the time but each text has 2-4 words, which don't fit the line width and are therefore broken up into multiple lines visually.
Here's the code:
String[] questionSplit = exercise.exerciseQuestion.split(" ");
ids = new Integer[questionSplit.length];
int displayWidth = getResources().getDisplayMetrics().widthPixels;
int currentLineWidth = 0;
Integer lastIdInRow = 0;
int counter = 0;
for(String bit : questionSplit) {
TextView tv = new TextView(this);
tv.setId(generateViewId());
ids[counter] = tv.getId();
//Exception for <br>
if(bit.equals("<br>")) {
lastIdInRow = ids[counter - 1];
currentLineWidth = 0;
} else {
tv.setText(bit);
tv.setPadding(dpToPx(3), dpToPx(3), dpToPx(2), dpToPx(2));
tv.measure(0, 0);
currentLineWidth += tv.getMeasuredWidth();
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
if(currentLineWidth <= displayWidth && counter == 0) {
// move along, nothing to see here
} else if(currentLineWidth <= displayWidth && counter != 0) {
p.addRule(RelativeLayout.RIGHT_OF, ids[counter - 1]);
} else {
lastIdInRow = ids[counter - 1];
currentLineWidth = 0;
}
if(lastIdInRow != 0 && lastIdInRow != tv.getId()) {
p.addRule(RelativeLayout.BELOW, lastIdInRow);
}
rlTextComparisonOriginal.addView(tv,p);
}
counter++;
}
To explain the layout rules of the TextViews: if the measuredWidth fits into the line, a RIGHT_OF the last id rule is added. If it would overflow, a BELOW the last id in the line rule is added.
As I mentioned earlier, for most of the text that works perfectly. But there are some words which do not fit. If I change the displayWidth to be only 80% of the display width, the error persists just the word changes, so I think it's not the specific text / word.
And here is the relevant part of the view's xml
<ScrollView
android:id="#+id/svTextComparisonDesc"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tvTextComparisonHeaderMiddle"
android:paddingBottom="55dp"
>
<RelativeLayout
android:id="#+id/rlTextComparison"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvTextComparisonDescription"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#color/text_background"
android:padding="10dp"
android:text="#string/text_exercise_desription"
android:textSize="#dimen/activity_text_description_size"
android:scrollHorizontally="false"
/>
<RelativeLayout
android:id="#+id/rlTextComparisonOriginal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/text_background"
android:layout_below="#id/tvTextComparisonDescription"
/>
<RelativeLayout
android:id="#+id/rlTextComparisonAnswer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/rlTextComparisonOriginal"
/>
</RelativeLayout>
</ScrollView>
The last bit of information: right now the code above resides in the activity's onCreate Method. If I log the measuredWidth and displayWidth and currentWidth, the logic isn't broken, the measuredWidth fits into the line, but after rendering, it doesn't.
Any ideas what the problem actually might be? Thanks in advance!
After using the mentioned lib the code is much cleaner and looks like this:
//Exception for <br>
if(bit.equals("<br>")) {
FlowLayout.LayoutParams lp = new FlowLayout.LayoutParams(0,0);
lp.setNewLine(true);
flTextComparisonOriginal.addView(tv,lp);
} else {
tv.setText(bit);
tv.setPadding(dpToPx(3), dpToPx(3), dpToPx(2), dpToPx(2));
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
flTextComparisonOriginal.addView(tv, p);
}
In case using a library is acceptable instead of coding it yourself, you will find two projects on github under the keyword "FlowLayout". These sound like they solve the layout you need:
https://github.com/ApmeM/android-flowlayout
https://github.com/blazsolar/FlowLayout
To get width and height of the text view,
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(text,0,text.length(),bounds);
int height = bounds.height();
int width = bounds.width();
I have a vertical LinearLayout with a multiline TextView set to have a layout_weight of 1, and below that a more complex layout that wraps its content. If there isn't enough room in the outer LinearLayout, I want the number of lines shown in the TextView to be reduced. Instead, the bottom half of the bottom line just gets clipped.
Is there any way around this? This is in an app widget, so I can't use custom views.
Simplified layout XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start|bottom"
android:orientation="vertical" >
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="fill_vertical"
android:maxLines="2" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<!-- ... sized content ... -->
</LinearLayout>
</LinearLayout>
A time ago I had to mess with this too, basically within an IRC client which receives hundreds of lines per tab, and sadly, the response is no, there's not any mechanism to automatically control the buffer of the TextView.
So I had to implement an infinite loop Thread (which I would later convert into a Service) which takes the number of lines of the current TextView and if it exceeds a certain amount, it's truncated from the beggining of the buffer (the oldest lines get removed).
I'll attach what have I done, maybe it might help you.
static void FreeTextBuffer() {
final TextView tv = (TextView) findViewById(R.id.your_textview);
final Spanned sptxt = (Spanned) tv.getText();
// This is a workaround, seems that Html.toHtml() passing directly the text makes the system stale - this works
final SoftReference<String> texto = new SoftReference<String>(Html.toHtml((Spanned) sptxt.subSequence(0, sptxt.length())));
final int matches = StringUtils.countMatches(texto.get(), "<br>");
if (matches > (3 * maxLines) / 2) {
// Here I'm counting the amount of \n to cut off (the 0.5 * matches is a tuned solution that works for me)
int cutpoint = -1;
for (int i = 0; i < 0.5 * matches; i++)
cutpoint = texto.get().indexOf("<br>", (cutpoint < 0)? 0 : cutpoint + 1);
// Just for the Thread...
final int forUIth = cutpoint;
if (cutpoint > -1) {
((Activity) globvars.getContext()).runOnUiThread(new Runnable() {
public void run() {
synchronized(tv) {
tv.setText(Html.fromHtml(texto.get().substring(forUIth)));
}
}
});
}
}
}
I am doing Robolectric testing on an app. (Robolectric 2.1 with ABS). In my fragment, I have a TextView with style:
<TextView android:id="#+id/homepage_title_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:paddingTop="#dimen/loading_textview_padding_top"
android:text="#string/loading_homepage_content"
android:textColor="#color/gray"
style="#android:style/TextAppearance.Medium"/>
Anytime that I try:
TextView homepageTitle = (TextView) mFragment.getView().findViewById(R.id.homepage_title_textview);
float textSize = homepageTitle.getTextSize();
It always returns 1.0. I have tested that the TextView has been created and visible with:
assertThat(homepageTitle.getVisibility(), equalTo(View.VISIBLE));
I have also changed the whole style="#android:style/TextAppearance.Medium" line to be android:textSize="18sp" instead to see if it would make a difference and it does not.
If it helps, here is my exact Robolectric test:
int style = android.R.style.TextAppearance_Medium;
int[] attrWanted = {android.R.attr.textSize};
TypedArray styleValues = Robolectric.application.getApplicationContext().obtainStyledAttributes(style, attrWanted);
String wantedTextSize = styleValues.getString(0);
String actualTextSize = String.valueOf(myTextView.getTextSize());
wantedTextSize returns "18sp"
actualTextSize returns "1.0"
I believe to get the text size of the textview.
String textSize = homepageTitle.getTextSize();
For that, you must specify a size
style="android:textSize="18sp""
does not qualify. But
android:textSize="18sp"
will qualify.
Hope this works.
I am pretty sure getTextSize() returns a float :P
Check this
Use:
float textSize = homepageTitle.getTextSize();
Is there any way in which I can display a long text on multiple columns?
For example I need to display an article, I have the entire String and I want to place it on 3 columns. How can I achieve this? Are there any libraries that can help me or do you know how should I approach this problem?
Any suggestion is appreciated. Thanks.
EDIT: The issue is the splitting of the string not the layout. I know I can use TableLayout... or weights... to distribute column evenly and so on. The problem is how do I split the String properly. Maybe 2 column would get filled and the 3rd just half of it? I don't know how to approach this, not the actual layout.
Check the TableLayout. To split your text you could split your text after 1/3 of your count of chars. Of cource you have to split the text at one whitespace charecter. UPDATE: See also my example code at the end of my posting.
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<TextView
android:text="#string/table_layout_4_open"
android:padding="3dip" />
<TextView
android:text="#string/table_layout_4_open_shortcut"
android:gravity="right"
android:padding="3dip" />
</TableRow>
<TableRow>
<TextView
android:text="#string/table_layout_4_save"
android:padding="3dip" />
<TextView
android:text="#string/table_layout_4_save_shortcut"
android:gravity="right"
android:padding="3dip" />
</TableRow>
</TableLayout>
For splitting you can test this code. The algorithem could maybe a little better be nearer to the split boundaries, but it works.
public static String[] getRows(String text, int rows) {
// some checks
if(text==null)
throw new NullPointerException("text was null!");
if(rows<0 && rows > 10)
throw new IllegalArgumentException("rows must be between 1 and 10!");
if(rows==1)
return new String[] { text };
// some init stuff
int len=text.length();
int splitOffset=0;
String[] ret=new String[rows];
Pattern whitespace = Pattern.compile("\\w+");
// do the work
for(int row=1;row<rows;row++) {
int end;
int searchOffset=len/rows*row;
// search next white space
Matcher matcher = whitespace.matcher(text.substring(searchOffset));
if(matcher.find() && !matcher.hitEnd()) {
// splitting on white space
end=matcher.end()+searchOffset;
} else {
// hard splitting if there are no white spaces
end=searchOffset;
}
ret[row-1]=text.substring(splitOffset, end);
splitOffset=end;
}
// put the remaing into the last element
ret[rows-1]=text.substring(splitOffset);
return ret;
}
Are you looking for a 'newspaper column' style? Once the first (fixed size) text-box fills, the text should continue into the other and so on?
If so, why not display your long string into a WebView where you can more easily achieve this using HTML and CSS?
use (Calculate text size according to width of text area)
Paint paint = new Paint();
Rect bounds = new Rect();
int text_height = 0;
int text_width = 0;
paint.setTypeface(Typeface.DEFAULT);// your preference here
paint.setTextSize(25);// have this the same as your text size
String text = "Some random text";
paint.getTextBounds(text, 0, text.length(), bounds);
text_height = bounds.height();
text_width = bounds.width();
to calculate how much is your text going to take space.
and calculate view.getWidth() about how much is your view width...
Then do the needful by dividing the text accordingly.
i have a string in the textView as:
<TextView
android:id="#+id/comment_concent"
android:maxLines="2"
android:textColor="#FFCD3333"
android:ellipsize="end"
android:layout_marginRight="5dip"
android:layout_width="210dip"
android:layout_height="50dip"
android:textSize="15sp"
android:text="aaddadadddddddddddddddddddddddddddddddddddddadddddddd"/>
sometime the text only "addadaddad",in other words the string length is not fixed,so if the string is too long,you know the end is show"...",my question is that how to know the string if end with"...",if the string is end with"...", i will call other methods to show the whole string.
Measure the text using paint object to see if it width is greater than textviews.
Paint paint = new Paint();
paint.setTextSize(textView.getTextSize());
final float size = paint.measureText(textview.getText());
if ((int)size > textView.getWidth()) {
// text is elipsized.
}
Edit:
Even better, just set textsize from textview instead of calculating, then measure text. Edited the above code.
Please look into this code. This will help you.
TextView textView=(TextView) yourtextviewId;
Layout l = textView.getLayout();
if ( l != null){
int lines = l.getLineCount();
if ( lines > 0)
if ( l.getEllipsisCount(lines-1) > 0)
Toast.makeText(getApplicationContext(), textView.getText().toString(), Toast.LENGTH_LONG).show();
}