How to show text as link starts with # - android

I am showing text as link in my text view by android:autoLink="web" property. And it showing successfuly. But now i also want to show text as link which starts from #, for example "FleeGroups" in word "User pressed FOH button of this post via #FleeGroups"

Use a Spanable String
public class MainActivity extends Activity {
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String s= "User pressed FOH button of this post via #FleeGroups";
tv = (TextView) findViewById(R.id.tv);
String split[] = s.split("#");
SpannableString ss1= new SpannableString(split[1]);
Log.i("....",""+split[0]+"........."+split[1]);
ss1.setSpan(new MyClickableSpan(split[1]), 0,split[1].length(), 0);
tv.append(split[0]);
tv.append(ss1);
tv.setMovementMethod(LinkMovementMethod.getInstance());
}
class MyClickableSpan extends ClickableSpan
{
String mystring;
public MyClickableSpan(String s)
{
mystring =s;
}
#Override
public void updateDrawState(TextPaint ds) {
// TODO Auto-generated method stub
super.updateDrawState(ds);
ds.setColor(Color.BLUE);
}
#Override
public void onClick(View widget) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, mystring, 1000).show();
}
}
}
More on styling #
http://www.chrisumbel.com/article/android_textview_rich_text_spannablestring
Snap shot
For reference if you need it later.
You can also use a regex to match words that start with #
String s= "User pressed #FOH button of this post via #FleeGroups some text";
Matcher matcher = Pattern.compile("#\\s*(\\w+)").matcher(s);
while (matcher.find()) {
spanstring= matcher.group(1);
Log.i(".............",spanstring);
}

You could use Html.fromHtml() and then set the LinkMovementMethod movement method.
Like this:
String link = "#FleeGroups";
String message = "User pressed FOH button of this post via ";
textView.setText(Html.fromHtml(message + link));
textView.setMovementMethod(LinkMovementMethod.getInstance());

/*Method in which you can pass the string to convert the into
spannableString and call this method form where ever you want
to set the text. It even work if you have mutiple # symbols
in your string.*/
TextView tv=(TextView) findViewById(R.id.textview);
tv.setText(getSpannableString("hi #StackOverFlow android"));
public SpannableStringBuilder getSpannableString(String str) {
SpannableStringBuilder builder = new SpannableStringBuilder();
String feed = str.replaceAll("\n", " ");
String[] individualfeed = feed.split(" ");
for (int i = 0; i < individualfeed.length; i++) {
if (individualfeed[i].contains("#")
) {
SpannableString redSpannable = new SpannableString(
individualfeed[i] + " ");
Pattern p = Pattern.compile(".*(\\w+)");
Matcher m = p.matcher(individualfeed[i]);
String str123 = null;
if (m.find()) {
str123 = m.group(1);
}
int startFrom = 0;
if (individualfeed[i].contains("#")) {
startFrom = individualfeed[i].indexOf("#");
}
if(individualfeed[i].trim().length()==1)
{
builder.append(individualfeed[i] + " ");
continue;
}
// I am using Green Color in this code change it accordingly
redSpannable.setSpan(
new ForegroundColorSpan(Color.parseColor("#00FF00")),
startFrom, individualfeed[i].lastIndexOf(str123) + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
final String tag = (String) individualfeed[i].subSequence(
startFrom, individualfeed[i].lastIndexOf(str123) + 1);
builder.append(redSpannable);
} else {
builder.append(individualfeed[i] + " ");
}
}
return builder;
}

Related

Bengali calculator Android studio

I am trying to build a Bengali calculator. Here is the layout of English calculator :
By editing layout I can easily replace English digits with Bengali digits. But when it comes to the calculation i am unable to do it. Like i want it to calculate in Bengali too. e.g it will perform in Bengali like this (২+২=৪) instead of (2+2=4). I have tried the replacing method but it didn't work.
Bengali digits(০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯)
English digits(1 2 3 4 5 6 7 8 9)
Thank you for your time.
public class MainActivity extends AppCompatActivity {
private TextView screen;
private String str2, result, str, sign;
private double a, b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
screen = (TextView) findViewById(R.id.textview);
str = "";
}
public void onclick(View v) {
Button button = (Button) v;
str += button.getText().toString();
screen.setText(str);
a = Double.parseDouble(str);
}
public void onclicksign(View v) {
Button button = (Button) v;
sign = button.getText().toString();
screen.setText(sign);
str = "";
}
public void calculate(View v) {
Button button = (Button) v;
str2 = screen.getText().toString();
b = Double.parseDouble(str2);
if (sign.equals("+")) {
result = a + b + "";
} else if (sign.equals("-")) {
result = a - b + "";
} else if (sign.equals("*")) {
result = a * b + "";
} else if (sign.equals("/")) {
result = a / b + "";
} else {
screen.setText("?????? ???");
}
{
screen.setText(result);
}
}
}
Your code tries to extract numerical values from the text on buttons.
You should write custom Double parser which parses Bengali number text to numerical value.
Also you should write a method which converts numerical double value to Bengali number text. You have to use this method while setting screen text.
public class MainActivity extends AppCompatActivity {
private TextView screen;
private String str2, result, str, sign;
private double a, b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
screen = (TextView) findViewById(R.id.textview);
str = "";
}
public void onclick(View v) {
Button button = (Button) v;
str += button.getText().toString();
screen.setText(str);
a = BengaliUtils.toDouble(str);
}
public void onclicksign(View v) {
Button button = (Button) v;
sign = button.getText().toString();
screen.setText(sign);
str = "";
}
public void calculate(View v) {
Button button = (Button) v;
str2 = screen.getText().toString();
b = BengaliUtils.toDouble(str2);
if (sign.equals("+")) {
result = a + b + "";
} else if (sign.equals("-")) {
result = a - b + "";
} else if (sign.equals("*")) {
result = a * b + "";
} else if (sign.equals("/")) {
result = a / b + "";
} else {
screen.setText("?????? ???");
}
{
screen.setText(BengaliUtils.toString(result));
}
}
}
class BengaliUtils {
static String toString(double value) {
//TODO implement logic
// You can convert value to regular number text, and then replace each char with the Bengali version. The performance could be improved with better logic.
return text;
}
static double toDouble(String text) {
//TODO implement logic
//You can do that, first replace each Bengali char with normal number char. The use Double.parse on new text. The performance could be improved with better logic.
return value;
}
}
#Override
public void onClick(View view) {
String num = editText.getText().toString();
//split the num
char[] charArray = num.toCharArray();
StringBuilder stringBuilder = new StringBuilder(charArray.length);
// loop and convert using switch case
for (int i=0; i<charArray.length; i++ ){
char character = charArray[i];
switch (character){
case '.':
stringBuilder.append(".");
break;
case '0':
stringBuilder.append("০");
break;
case '1':
stringBuilder.append("১");
break;
}
}
//Final result..
textView.setText(stringBuilder);
}
Try above code...
Here is the output
NOTE
I am taking English numbers from EditText on Button click. You will
have to change that in your code.
Currently, switch can handle 0,1,.(decimal) only. You can easily
add cases for other numbers too.
Please Check this answer too. Convert String to another locale in java

Android - get text position from textview with html data

I have set html data to my textview. When I select any word/characters from textview I want to bold that word and replace original html data with new one.
String html = "<p>hello this is android testing</p>";
Like this my html maybe have many html tags in it. If I want to make "android" word bold, how can I replace original html string with "android".
I want <p>hello this is <strong>android</strong> testing</p> as result.
You can first set you string content into the TextView and then use setCustomSelectionActionModeCallback(...) to intercept the selection within the TextView.
In the example bellow a selected word will be surrounded by <strong>...</strong>.
For example selecting "testing" will make the following string visible into the TextView.
hello this is android testing android bla bla android bla bla android bla
Then selecting the last instance on "android" in the already transformed TextView content will make the following string visible into the TextVIew.
hello this is android testing android bla bla android bla bla android bla
Code :
public class MainActivity extends AppCompatActivity {
String yourString = "<p>hello this is android testing android bla bla android bla bla android bla</p>";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView)findViewById(R.id.opening_today);
tv.setText(Html.fromHtml(yourString));
tv.setCustomSelectionActionModeCallback(new CallbackListener(tv));
}
class CallbackListener implements ActionMode.Callback{
private TextView tv;
private String strongS = "<strong>";
private String strongE = "</strong>";
public CallbackListener(TextView tv) {
this.tv = tv;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
int start = tv.getSelectionStart();
int end = tv.getSelectionEnd();
if( start == 0 && end == 0)
return false;
String content = tv.getText().toString();
String token = content.substring(start, end);
String before = content.substring(0, start);
String after = content.substring(end, content.length());
content = makeItStrong(before, after, token);
tv.setText(Html.fromHtml(content));
return false;
}
private String makeItStrong(String before, String after, String token){
return cleanTags(before, strongS, strongE) + strongS + token + strongE + cleanTags(after, strongS, strongE);
}
private String cleanTags(String source, String... exp){
for(String s: exp){
source = source.replace(s, "");
}
return source;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return true; }
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
#Override
public void onDestroyActionMode(ActionMode mode) {}
}
}
Use SelectableTextView to get the selected text. You can see this implementation on github here.
Check the answer here. This might help you
And you can make bold using tag,
String string= "<b>" + android + "</b> " + remainingString;
textView.setText(Html.fromHtml(string));
With the following code, you can highlight formatted text more than once and each time you can get the cumulative result of all highlights.
int getOccuranceNumber(String text ,String selection, int selectionStartIndex){
int index = text.indexOf(selection);
int occuranceNumber = 0;
while (index >= 0) {
if(index == selectionStartIndex){
return occuranceNumber;
}else {
index = text.indexOf(selection, index + 1);
occuranceNumber++;
}
}
return occuranceNumber;
}
int getOccuranceIndex(String text ,String selection, int occuranceNumber){
int index = text.indexOf(selection);
int i = 0;
while (i!=occuranceNumber) {
index = text.indexOf(selection, index + 1);
i++;
}
return index;
}
public String toHex(String arg) {
TextView textV = new TextView(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textV.setText(Html.fromHtml(arg,Html.FROM_HTML_MODE_LEGACY));
}else{
textV.setText(Html.fromHtml(arg));
}
String textFormated ="";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textFormated = Html.toHtml((Spanned) textV.getText(),TO_HTML_PARAGRAPH_LINES_CONSECUTIVE).toString();
}else{
textFormated = Html.toHtml((Spanned) textV.getText()).toString();
}
return textFormated.replace("<p dir=\"rtl\">","").replace("</p>","").replace("\n","");
}
public void highLightText(TextView textView){
String textFormated ="";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textFormated = Html.toHtml((Spanned) textView.getText(),TO_HTML_PARAGRAPH_LINES_CONSECUTIVE).toString();
}else{
textFormated = Html.toHtml((Spanned) textView.getText()).toString();
}
String text = textView.getText().toString();
String selection = text.substring(textView.getSelectionStart(),textView.getSelectionEnd());
int occuranceNum = getOccuranceNumber(text,selection,textView.getSelectionStart());
String selectionHex = toHex(selection);
int formatedTextSelectionStart = getOccuranceIndex(textFormated,selectionHex,occuranceNum);
if(formatedTextSelectionStart<0)return;
int formatedTextSelectionEnd = formatedTextSelectionStart + selectionHex.length();
String formatedTextPart1 = textFormated.substring(0,formatedTextSelectionStart);
String formatedTextPart2 = textFormated.substring(formatedTextSelectionStart,formatedTextSelectionEnd);
String formatedTextPart3 = textFormated.substring(formatedTextSelectionEnd,textFormated.length());
String colorOpenTag="<font color=\"#f7c627\">";
String colorCloseTag="</font>";
String finalText = formatedTextPart1+colorOpenTag+formatedTextPart2+colorCloseTag+formatedTextPart3;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textView.setText(Html.fromHtml(finalText,Html.FROM_HTML_MODE_LEGACY));
}else{
textView.setText(Html.fromHtml(finalText));
}
}

Registering separate clicks for every Spanned string

My app need such scenario like in a textView I stored "#dev will goto home and #Roy will go to Station. I want to open a dialer activity to call the clicked person.
But using this code if I click on any #words it shows whole string.
am toasted string.
User can enter his own string and may be he/she enter or not the #contact and there is not defined index of the same.
multiAutoCompleteTextView.setText(addClickablePart(desc), TextView.BufferType.SPANNABLE);
private SpannableString addClickablePart(String str) {
SpannableString ss = new SpannableString(str);
Pattern pattern = Pattern.compile("[#]\\w*");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
// do toasting
TextView b = (TextView)textView;
String buttonText = b.getText().toString();
Toast.makeText(ViewNote.this,buttonText,Toast.LENGTH_SHORT).show();
}
};
ss.setSpan(clickableSpan, matcher.start(), matcher.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return ss;
}
You need to store the text which is associated with each ClickableSpan. Try something like this:
public static class ClickableSegmentSpan extends ClickableSpan {
private String segment;
public ClickableSegmentSpan(String segment) {
this.segment = segment;
}
#Override
public void onClick(View widget) {
Toast.makeText(widget.getContext(), segment, Toast.LENGTH_SHORT).show();
}
}
The addClickablePart method would change to this:
private SpannableString addClickablePart(String str) {
SpannableString ss = new SpannableString(str);
Pattern pattern = Pattern.compile("[#]\\w*");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
ss.setSpan(new ClickableSegmentSpan(str.substring(start, end)), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return ss;
}

text colors for one TextView using two Linkify's and weblinks clickable

I want twitter mentions to be in redcolor and hashtags is another color,if any tweet contains any weblinks.. links should be clickable and passed through intent to another Activity(WebView).
How can I achieve this ??
TransformFilter filter = new TransformFilter() {
public final String transformUrl(final Matcher match, String url) {
return match.group();
}
};
Pattern mentionPattern = Pattern.compile("#([A-Za-z0-9_-]+)");
String mentionScheme = "http://www.twitter.com/";
Linkify.addLinks(tvMessage, mentionPattern, mentionScheme, null, filter);
Pattern hashtagPattern = Pattern.compile("#([A-Za-z0-9_-]+)");
String hashtagScheme = "http://www.twitter.com/search/";
Linkify.addLinks(tvMessage, hashtagPattern, hashtagScheme, null, filter);
Pattern urlPattern = Patterns.WEB_URL;
Linkify.addLinks(tvMessage, urlPattern, null, null, filter);
// tvMessage.setLinkTextColor(Color.parseColor("#3467BB"));
Finally i have achieved hashtags weblinks clickable and made them very attractive by keeping different colors using android sdk SpannableString and it's ClickableSpan .
private void Linkfiy(String a, TextView textView) {
Pattern urlPattern = Patterns.WEB_URL;
Pattern mentionPattern = Pattern.compile("(#[A-Za-z0-9_-]+)");
Pattern hashtagPattern = Pattern.compile("#(\\w+|\\W+)");
Matcher o = hashtagPattern.matcher(a);
Matcher mention = mentionPattern.matcher(a);
Matcher weblink = urlPattern.matcher(a);
SpannableString spannableString = new SpannableString(a);
//#hashtags
while (o.find()) {
spannableString.setSpan(new NonUnderlinedClickableSpan(o.group(),
0), o.start(), o.end(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// --- #mention
while (mention.find()) {
spannableString.setSpan(
new NonUnderlinedClickableSpan(mention.group(), 1), mention.start(), mention.end(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
//#weblink
while (weblink.find()) {
spannableString.setSpan(
new NonUnderlinedClickableSpan(weblink.group(), 2), weblink.start(), weblink.end(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
NonUnderlinedClickableSpan class
public class NonUnderlinedClickableSpan extends ClickableSpan {
int type;// 0-hashtag , 1- mention, 2- url link
String text;// Keyword or url
String time;
public NonUnderlinedClickableSpan(String text, int type) {
this.text = text;
this.type = type;
this.time = time;
}
#Override
public void updateDrawState(TextPaint ds) {
//adding colors
if (type == 1)
ds.setColor(InstagramIndetail.this.getResources().getColor(
R.color.link_color_mention));
else if (type == 2)
ds.setColor(InstagramIndetail.this.getResources().getColor(
R.color.link_color_url));
else
ds.setColor(InstagramIndetail.this.getResources().getColor(
R.color.link_color_hashtag));
ds.setUnderlineText(false);
// ds.setTypeface(Typeface.DEFAULT_BOLD);
}
#Override
public void onClick(View v) {
Debug.e("click done", "ok " + text);
if (type == 0) {
//pass hashtags to activity using intents
} else if (type == 1) {
//do for mentions
} else {
// passing weblinks urls to webview activity
startWebViewActivity(text);
}
}
}

Multiple clickspans in a textview

I have a function to build clickable tags for a textview. It goes as follows:
private CharSequence tagsBuilder(String text, String token) {
SpannableStringBuilder builtTags = new SpannableStringBuilder();
int start = 0, end = 0;
for(int i = 0; i < 5; i++) {
start = 0;
end = text.indexOf(token, 0);
try {
if(start < end) {
SpannableStringBuilder ssb = new SpannableStringBuilder(text.substring(start, end));
ssb.setSpan(new ClickableSpan() {
#Override
public void onClick(View v)
{
Log.i("DEBUGTAG", "Span clicked - " + ((TextView) v).getText());
}
}, start, end, 0);
builtTags.append(ssb);
builtTags.append(" ");
text = text.substring(end + 1);
}
} catch (IndexOutOfBoundsException e) {
break;
}
}
return builtTags;
}
I can see the textview with 5 individually clickable tags. But the problem is, the Log that prints for any tag that is clicked is whole text of the textview.
Am I doing something wrong here? How do I get the text of individual tags that were clicked.
Your log line is the following:
Log.i("DEBUGTAG", "Span clicked - " + ((TextView) v).getText());
That logs the contents of the TextView. So... you get the text of the TextView. If you want to get token in there, you'll have to copy that in.
Here's something you can try:
private CharSequence tagsBuilder(String text, final String token) {
SpannableStringBuilder builtTags = new SpannableStringBuilder();
int start = 0, end = 0;
for(int i = 0; i < 5; i++) {
start = 0;
end = text.indexOf(token, 0);
try {
if(start < end) {
SpannableStringBuilder ssb = new SpannableStringBuilder(text.substring(start, end));
ssb.setSpan(new ClickableSpan() {
private String mText = token;
#Override
public void onClick(View v)
{
Log.i("DEBUGTAG", "Span clicked - " + mText);
}
}, start, end, 0);
builtTags.append(ssb);
builtTags.append(" ");
text = text.substring(end + 1);
}
} catch (IndexOutOfBoundsException e) {
break;
}
}
return builtTags;
}

Categories

Resources