Dealing with long Strings & TextView behavior - java

I’m developing an android app that gets objects from a server and shows them in a simple list.
I’m trying to figure out how to deal with long object’s titles :
Every title populates a designated multi-line TextView.
If a title is longer than 16 characters, it messes with my desired UI.
There are two scenarios I need to solve -
1). If the title is longer than 16 characters & contains more than one word, I need to split the words into different lines (I tried to .split("") and .trim(), but I don’t want to use another view, just break a line in the same one, and the use in ("") seems unreliable to me).
2). If the title is longer than 16 characters and contains only one long word, I only need to change font size specifically.
Any ideas for a good and reliable solution?
Thanks a lot in advance.

use SpannableString for a single view
For title:
SpannableString titleSpan = new SpannableString("title String");
titleSpan.setSpan(new RelativeSizeSpan(1.3f), 0, titleSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
for Message
SpannableString messageSpan = new SpannableString("Message String");
messageSpan.setSpan(new RelativeSizeSpan(1.0f), 0, messageSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
set in TextView
tvTermsPolicyHeading.setText(TextUtils.concat(titleSpan, messageSpan));

Code like below it will work as you need
String title; //your title
//find length of your title
int length = title.length();
if (length>16){
string[] titles = myString.split("\\s+");
int size = titles.length;
if (size < 2){
yourTextview.setText(title);
// reduce the text size of your textview
}else {
String newTitle= "";
for (int i=0;i<titles.length;i++){
newTitle = titles[i]+"\n"
}
yourTextview.setText(newTitle);
}
}

You can split and then concatenate the words using "\n" if there are more than one words.
In case of long word
You can see this question here
Auto-fit TextView for Android

try this:
if(title.split(" ").size > 1){
String line1 = title.substring(0, 16);
int end = line1.lastIndexOf(" ");
titleTextView.setText(title.substring(0,end) + "\n" +
title.substring(end+1,title.size-1);
}else{
titleTextView.setText(title);
titleTextView.setTextSize(yourTextSize);
}
this code should work perfectly for your case.

Related

Changing HTML to PlainText

I'm trying to edit HTML to be plaintext in java, but I am running into an issue. I am trying to get the number on the padding-left element in the code and transform it into tabs but it doesn't work.
ie.
<p style="padding-left:40px;">Hello</p> becomes Hello with a tab in front of it.
Here is my code so far (every 40px becomes one tab)
private static String setNonHTML(String txt)
{
System.out.println(txt.substring(txt.indexOf("<p style=\"padding-left:") + 23, txt.indexOf("px\"><b>")));
//return "";
return txt
.replaceAll("<br>","\n")
.replaceAll(txt.substring(txt.indexOf("<p style=\"padding-left:"), txt.indexOf("px\"><b>") + 7)
,"\n" + repeat("\t",Integer.parseInt(txt.substring(txt.indexOf("<p style=\"padding-left:") + 23, txt.indexOf("px\"><b>")))/40))
.replaceAll(txt.substring(txt.indexOf("<p style=\"padding-left:"), txt.indexOf("px\">") + 4)
,"\n" + repeat("\t",Integer.parseInt(txt.substring(txt.indexOf("<p style=\"padding-left:") + 23, txt.indexOf("px\">")))/40))
.replaceAll("(?s)<[^>]*>(\\s*<[^>]*>)*", "\n");
}
I cleaned up some of your code to show you what is happening
private static String setNonHTML(String txt)
{
System.out.println(txt.substring(txt.indexOf("<p style=\"padding-left:") + 23, txt.indexOf("px\"><b>")));
//return "";
//grab the padding text indexes
int beforePaddingIndex = txt.indexOf("<p style=\"padding-left:");
int afterPaddingIndex = txt.indexOf("px\"><b>");
//replace all breaks with new lines
txt = txt.replaceAll("<br>", "\n");
//replaces all instances of 40px\"> with \n\t
txt = txt.replaceAll(txt.substring(beforePaddingIndex, afterPaddingIndex + 7), "\n" + repeat("\t", Integer.parseInt(txt.substring(beforePaddingIndex + 23, afterPaddingIndex)) / 40));
//the indexes of these items have changed because the last operation replaced them. The following items will not have indexes due to the replace operation.
beforePaddingIndex = txt.indexOf("<p style=\"padding-left:");
afterPaddingIndex = txt.indexOf("px\"><b>");
afterPaddingBeforeBoldIndex = txt.indexOf("px\">");
//replace a substring of the same tag a second time? should find nothing
txt = txt.replaceAll(txt.substring(beforePaddingIndex, afterPaddingIndex), "\n" + repeat("\t", Integer.parseInt(txt.substring(beforePaddingIndex + 23, afterPaddingBeforeBoldIndex)) / 40));
txt = txt.replaceAll("(?s)<[^>]*>(\\s*<[^>]*>)*", "\n");
return txt;
}
as you can see, after the first replace all, there is a second replace all that takes place on virtually the same indexes. You grab the index of values inline after the first replace all so I set them again to replicate that behavior. Splitting out code into descriptive variables and sections is a good practice and is monumentally helpful when trying to debug complicated sections. I don't know what the output of your program is giving you, so I have no way to know if this actually solves your issue, but it does look like a bug and I believe this might give you a good start.
As for what you should do to fix this, you may want to look into some off the shelf solution like http://htmlcleaner.sourceforge.net/javause.php
That allows you to traverse and modify html programmatically and read off attributes like padding left and the extract content between tags.

Styling Two First Words With Spannable String

I am trying to give some style effect (like bold, strikethrough) to the first two words in a string.
The way I am doing it is inspired by this thread.
String[] tokens = text.split(" ");
String twoFirstWords = tokens[0] + " " + tokens[1]; //two first words
String content = text.replaceFirst(twoFirstWords, " "); //the rest
SpannableStringBuilder builder = new SpannableStringBuilder();
SpannableString span1 = new SpannableString(twoFirstWords);
SpannableString span2 = new SpannableString(content);
span1.setSpan(new StyleSpan(Typeface.BOLD), 0, twoFirstWords.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
span1.setSpan(new StrikethroughSpan(),0, twoFirstWords.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE );
span1.setSpan(new CustomTypefaceSpan("", fontFirst), 0, twoFirstWords.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
span2.setSpan(new CustomTypefaceSpan("", fontContent), 0, content.length(), Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
builder.append(span1);
builder.append(span2);
textView.setText(builder, TextView.BufferType.SPANNABLE);
Based on code above, I am trying to give BOLD and Strikethrough effect only to the two first words.. However, those effects are also applied to the content.
This code worked fine when I applied style for two last words in a string, but keep failing when using first words. I suspect this is because of wrong start and end of .SetSpan (Or maybe that is not the case)... I am also still clueless at finding the right index for start and end.. Anyone can help me to fix this issue? Thank you.
Yes, you can do this. The way I'd do this (since it's relatively simple stuff) is just with HTML. So you can do something like this...
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(Html.fromHtml("<b><strike>" + twoFirstWords
+ "</b></strike>" + restOfTheSentence));
CommonsWare has a great blog post that list all of the tags that this supports that you can find here.
Ok, we have a conclusion. Thanks to pskink!
What I need to do, so the effect is not applied to content is using SPAN_EXCLUSIVE_EXCLUSIVE. Like below:
span1.setSpan(new StyleSpan(Typeface.BOLD), 0, twoFirstWords.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

Issue in Combining splitted String

I have extracted text from "web 2.0 wikipedia" article, and splitted it into "sentences". After that, I am going to create "Strings" which each string containing 5 sentences.
When extracted, the text looks like below, in EditText
Below is my code
finalText = textField.getText().toString();
String[] textArrayWithFullStop = finalText.split("\\. ");
String colelctionOfFiveSentences = "";
List<String>textCollection = new ArrayList<String>();
for(int i=0;i<textArrayWithFullStop.length;i++)
{
colelctionOfFiveSentences = colelctionOfFiveSentences + textArrayWithFullStop[i];
if( (i%5==0) )
{
textCollection.add(colelctionOfFiveSentences);
colelctionOfFiveSentences = "";
}
}
But, when I use the Toast to display the text, here what is gives
Toast.makeText(Talk.this, textCollection.get(0), Toast.LENGTH_LONG).show();
As you can see, this is only one sentence! But I expected it to have 5 sentences!
And the other thing is, the second sentence is starting from somewhere else. Here how I have extracted it into Toast
Toast.makeText(Talk.this, textCollection.get(1), Toast.LENGTH_LONG).show();
This make no sense to me! How can I properly split the text into sentences and, create Strings containing 5 sentences each?
The problem is that for the first sentence, 0 % 5 = 0, so it is being added to the array list immediately. You should use another counter instead of mod.
finalText = textField.getText().toString();
String[] textArrayWithFullStop = finalText.split("\\. ");
String colelctionOfFiveSentences = "";
int sentenceAdded = 0;
List<String>textCollection = new ArrayList<String>();
for(int i=0;i<textArrayWithFullStop.length;i++)
{
colelctionOfFiveSentences += textArrayWithFullStop[i] + ". ";
sentenceAdded++;
if(sentenceAdded == 5)
{
textCollection.add(colelctionOfFiveSentences);
colelctionOfFiveSentences = "";
sentenceAdded = 0;
}
}
add ". " to textArrayWithFullStop[i]
colelctionOfFiveSentences = colelctionOfFiveSentences + textArrayWithFullStop[i]+". ";
I believe that if you modify the mod line to this:
if(i%5==4)
you will have what you need.
You probably realize this, but there are other reasons why someone might use a ". ", that doesn't actually end a sentence, for instance
I spoke to John and he said... "I went to the store.
Then I went to the Tennis courts.",
and I don't believe he was telling the truth because
1. Why would someone go to play tennis after going to the store and
2. John has no legs!
I had to ask, am I going to let him get away with these lies?
That's two sentences that don't end with a period and would mislead your code into thinking it's 5 sentences broken up at entirely the wrong places, so this approach is really fraught with problems. However, as an exercise in splitting strings, I guess it's as good as any other.
As a side problem(splitting sentences) solution I would suggest to start with this regexp
string.split(".(\\[[0-9\\[\\]]+\\])? ")
And for main problem may be you could use copyOfRange()

Selection Indexes are not same to getText indexes

i'm new to java, start a project 7 days ago, today with some folks from this place i successed to pass through one problem, but still there's one more...
in last problem i needed to search an string and highlight it, but now, my problem is:
Why selection index are not same to the indexes i search for after some unknown character which i dont know my self :|
this is my button code:
int startFrom = jEditorPane1.getSelectionStart();
if(jEditorPane1.getSelectionStart() == jEditorPane1.getSelectionEnd()){
startFrom = -1;
}
String searchWord = jTextField3.getText();
int searchIndex = jEditorPane1.getText().indexOf(searchWord, startFrom + 1);
if(searchIndex != -1){
jEditorPane1.requestFocusInWindow();
jEditorPane1.select(searchIndex, searchIndex+searchWord.length());
}
else{
jEditorPane1.setSelectionStart(0);
jEditorPane1.setSelectionEnd(0);
}
and i'm sure that i need to do some string processing, to convert string index to swing jEditorPane/JTextPane index
for example:
i search for do in string like this:
"Hey,
How do you do?"
and it highlight it this way:
"Hey,
How doyou do?"
which mean it started one index forther that what it should, and in here it's casue escape char of \n and i dont know, cause some time it happen in single row text...
how can i get ride of this?
See Text and New Lines for more information and a solution. The basics of this link is to use:
int length = textPane.getDocument().getLength();
String text = textPane.getDocument().getText(0, length);
The above will only return "\n" as the EOL string so the offsets will match when you do a search and then select the text.

How to format text string sent via Share menu

I use the following code to get TEXT sent to my app from other apps via Share menu, and display the TEXT in an EditText.
Intent receivedIntent = getIntent();
String receivedAction = receivedIntent.getAction();
String receivedType = receivedIntent.getType();
TextView txtView = (EditText) findViewById(R.id.edWord);
//if(receivedAction.equals(Intent.ACTION_SEND)){
if (Intent.ACTION_SEND.equals(receivedAction) && receivedType != null) {
if(receivedType.startsWith("text/")) {
String receivedText = receivedIntent.getStringExtra(Intent.EXTRA_TEXT).toLowerCase();
if (receivedText != null)
{
txtView.setText(receivedText);
txtView.requestFocus();
ListView myList=(ListView) findViewById(R.id.lstWord);
myList.setFocusableInTouchMode(true);
myList.setSelection(0);
}
else
txtView.setText("");
}
}
Everything works well, i.e., the sent text is displayed in my EditText (namely edWord in the above code). But the problem is the text sent via Share sometimes consists of meaningless elements or derivatives, e.g.: "word, word', word, or looked, books, tomatoes.
Now what I want is to format the text so that it contains only real word or the base form of the word before it is added to EditText.
I've heard about approximate string matching or fuzzy searching but I have no idea how to apply it to my code. I wonder whether you can give me a little help to solve the above problem, at least with formatting/stripping non-word elements.
Thanks in advance.
I think I have found the answer for the first part of my question, i.e., removing non-word elements from a string (starting and/or ending a string). Here is the code with a bit of Regex algorithm that I use:
String receivedText = receivedIntent.getStringExtra(Intent.EXTRA_TEXT);
if (receivedText != null)
{
receivedText = receivedText.toLowerCase();
//Remove all non-word elements starting and/or ending a string
String strippedInput = receivedText.replaceAll("^\\W+|\\W+$", "");
System.out.println("Stripped string: " + strippedInput);
txtView.setText(strippedInput);
txtView.requestFocus();
ListView myList=(ListView) findViewById(R.id.lstWord);
myList.setFocusableInTouchMode(true);
myList.setSelection(0);
}
For the second part of my question, which is about fuzzy searching, I guess it more or less involves re-coding how my app searches for results from its SQLlite database. This is still my un-answered question.

Categories