Setting minimum length for auto link - android

I have a big paragraph which may have numbers, email addresses and links. So I have to set setAutoLinkMask(Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES | Linkify.WEB_URLS) for my textview.
The content may contain digits of varying numbers. I want to set numbers having atleast 8 digits as phone number links.(For Eg : 12345678)
Is it possible to set minimum length for Linkify.PHONE_NUMBERS ?
Is there anyway to achieve this?

In case you can use Linkify.MatchFilter to specify minimum length or your some other requirements. There is not any direct way provided by Android.
Also somewhere in this SO post found some good examples.

use below pattern :
SpannableString buffer = new SpannableString(text);
Pattern pattern = Pattern.compile("^[0-9]\d{7,9}$");
Linkify.addLinks(buffer , pattern,"");

Yes, its possible. I researched this phenomenon :-)
To set the minimum length for a phone number, use this code:
private final Linkify.MatchFilter matchFilterForPhone = new Linkify.MatchFilter() {
#Override
public boolean acceptMatch(CharSequence s, int start, int end) {
int digitCount = 0;
for (int i = start; i < end; i++) {
if (Character.isDigit(s.charAt(i))) {
digitCount++;
if (digitCount >= 6) { // HERE: number 6 is minimum
return true;
}
}
}
return false;
}
};
To properly format and link phone numbers, use:
final SpannableString s = new SpannableString(myTekst);
Linkify.addLinks(s, android.util.Patterns.PHONE, "tel:", matchFilterForPhone, Linkify.sPhoneNumberTransformFilter);
Now place the formatted s in your TextView, and call:
findViewById(R.id.message).setLinkTextColor(Color.BLUE);
findViewById(R.id.message).setMovementMethod(LinkMovementMethod.getInstance());
That's all. Thanks for vote.

Related

How to count characters in a unicode string (Hindi / Marathi) in android

I have an EditText to get description and want to set max length 145 chars.
I have set maxlength 145 in XML. This works correctly for English.
But for languages other than English, being specific, Marathi, Hindi etc it doesn't work properly. I counts each symbol as separate character.
For example: "व्ही"
this is considered as one character in Hindi, and it's length should be 1, but it returns me length 2.
I have seen the solution in this link
But it doesn't work for Hindi/Marathi language because it cannot detect connected characters. How to detect connected characters?
Thanks in advance :)
Plz try this code
String str = "व्ही";
int count = 0;
for(int i=0; i<str.length(); i++)
{
if(!isMark(str.charAt(i)))
count++;
}
textview.setText(count);
Try this:
import java.text.BreakIterator;
import java.util.Locale;
public class MyClass {
private int graphemeClusterCount(Locale locale) {
String text = "व्ही";
BreakIterator breakIterator = BreakIterator.getCharacterInstance(locale);
breakIterator.setText(text);
int count = 0;
int start = breakIterator.first();
for (int end = breakIterator.next();
end != BreakIterator.DONE;
start = end, end = breakIterator.next()) {
count++;
}
return count;
}
}
Some references:
Unicode FAQ on what it calls grapheme clusters: http://unicode.org/faq/char_combmark.html#7
Sample code from Android documentation: https://developer.android.com/reference/java/text/BreakIterator.html
ICU has a BreakIterator implementation, too: http://site.icu-project.org/ and you can import in Gradle:
compile 'com.ibm.icu:icu4j:58.2'

Android phone number mask for EditText

I'm developing application for Android. In this app user needs sign up and he needs type phone number. I want make mask for this text field in format like +7 (999) 999-99-99. I've tried use mPhoneNumberEditText.addTextChangedListener(new PhoneNumberFormattingTextWatcher()); but it provides only (999) 999-9999 format.
How can I do format which I need?
The most effective way to use a mask on EditText in your Android programs in Android Studio is to use MaskedEditText library (GitHub link).
It's a kind of custom EditText with Watcher that allows you to set a hint with different color (if you want if will be available even when user already started to type), mask and it's very easy to use :-)
compile 'ru.egslava:MaskedEditText:1.0.5'
<br.com.sapereaude.maskedEditText.MaskedEditText
android:id="#+id/phone_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone"
android:typeface="monospace"
mask:allowed_chars="1234567890"
mask:mask="+7(###)###-##-##"
app:keep_hint="true"
/>
And that is!
The format you are looking for is used in Russia.
Use the following code for it:
String data = PhoneNumberUtils.formatNumber("9999999999", "RU");
Log.i("Number", data);
The first parameter is your number string and second one is the ISO code of the country.
Useful Links: Android Docs, Phone Number formats of different countries, ISO code of countries
This plugin can help:
https://github.com/pinball83/Masked-Edittext
<com.github.pinball83.maskededittext.MaskedEditText
android:id="#+id/masked_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
app:mask="+7 (***) ***-**-**"
app:notMaskedSymbol="*"/>
I am sharing my piece of code with to give you an idea, how could you do it.
I did it for my project a long ago, I hope you could figure out how the following number XXXXXXXXXXXXX converted into XXXXX-XXXXXXX-X in textwatcher
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
int i = et_cnic.getText().toString().length();
if (i < 6)
len = 0;
if (i == 6 && len < 7) {
len = 7;
String ss = s.toString();
String first = ss.substring(0, ss.length() - 1);
String last = ss.substring(ss.length() - 1);
et_cnic.setText(first + "-" + last);
et_cnic.setSelection(et_cnic.getText().length());
}
if (i < 14)
len2 = 0;
if (i == 14 && len2 < 14) {
len2 = 14;
String ss = s.toString();
String first = ss.substring(0, ss.length() - 1);
String last = ss.substring(ss.length() - 1);
et_cnic.setText(first + "-" + last);
et_cnic.setSelection(et_cnic.getText().length());
}
}

TextView with mixed languages

I have a TextView with 2 lines. first line rtl language (let's say hebrew), second line is ltr language (let's say english)
The View result is something like:
אחת שתיים שלוש
one two three
what i want: align rtl in that case
אחת שתיים שלוש
one two three
I've tried using setTextDirection() with TEXT_DIRECTION_FIRST_STRONG
but alas the results were the same. Also tried TEXT_ANY_RTL without success
myTextView.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
if i'm using TEXT_DIRECTION_RTL it's working as expected but this is not really a solution because most of the time the TextView will contain only one language.
Is this solvable?
--- UPDATE ---
How i'm populating the TextView
SpannableStringBuilder ssb = new SpannableStringBuilder(titleText);
int end = titlText.length();
ssb.append("\n").append(otheText);
ssb.setSpan(new AbsoluteSizeSpan(size), end, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ssb);
Why not just use two TextViews?
I've managed to solve this problem using Character.getDirectionality.
The first char that is a directional char will signify the TextView direction
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static int getTextDirection(String text) {
final int length = text.length();
for (int i = 0; i < length; i++) {
final char c = text.charAt(i);
final byte directionality = Character.getDirectionality(c);
if(directionality == Character.DIRECTIONALITY_LEFT_TO_RIGHT){
return View.TEXT_DIRECTION_LTR;
}
else if(directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT){
return View.TEXT_DIRECTION_RTL;
}
}
return View.TEXT_DIRECTION_ANY_RTL;
}
and then:
textView.setTextDirection(textDirection);
I Strongly believe that TEXT_DIRECTION_FIRST_STRONG is supposed to do the exact same thing according to the docs. sadly it's not the case.
I'm not accepting my answer in hope that someone will suggest better solution
What About TEXT_DIRECTION_ANY_RTL
This text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. If there are neither, the paragraph direction is the view's resolved layout direction.

Custom fonts for TextView based on languages inside String

I have two font ttf files that must be applied on a TextView based on languages inside String. So e.g. consider this sample text:
hey what's up ضعيف
I can just apply a typeface span based on language but it requires custom markup in every string that is fetched from our server e.g.
<ttf1>hey what's up <ttf1><ttf2>ضعيف</ttf2>
And parsing every String at run time will give a performance hit. Is there any other approach to achieve this?
For start lets say I need to do this just for direction of text i.e. RTL and LTR so in above example English is LTR and Arabic is RTL. Will this be any different?
I have tried merging those two font files but there are line height issues and if I fix it for one font file it gets broken for other file.
I found a more elegant solution than manual markup with help of someone:
String paragraph = "hey what's up ضعيف";
int NO_FLAG = 0;
Bidi bidi = new Bidi(paragraph, NO_FLAG);
int runCount = bidi.getRunCount();
for (int i = 0; i < runCount; i++) {
String ltrtl = bidi.getRunLevel(i) % 2 == 0 ? "ltr" : "rtl";
String subString = paragraph.substring(bidi.getRunStart(i), bidi.getRunLimit(i));
Log.d(">>bidi:" + i, subString+" is "+ltrtl);
}
prints:
hey what's up is ltr
ضعيف is rtl
So now one can easily build TypefaceSpan or MetricAffectingSpan based on language direction like this:
SpannableString spanString = new SpannableString(paragraph);
for (int i = 0; i < runCount; i++) {
Object span = bidi.getRunLevel(i) % 2 == 0 ? ltrFontSpan : rtlFontSpan;
spanString.setSpan(span, bidi.getRunStart(i), bidi.getRunLimit(i), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
textView.setText(spanString);

Small Caps on TextViews, EditTexts, and Buttons in Android

Is there something I can do to make the text look in small caps/capital? As described here: http://en.wikipedia.org/wiki/Small_caps. I used a converter but some characters are missing.
EDIT 2015-08-02: As of API 21 (Lollipop) you can simply add:
android:fontFeatureSettings="smcp"
to your TextView declaration in XML, or at runtime, invoke:
textView.setFontFeatureSettings("smcp");
Of course, this only works for API 21 and up, so you'd still have to handle the old solution manually until you are only supporting Lollipop and above.
Being a bit of a typography geek at heart, this seemed like a really good question. I got to learn some more about Unicode today, as well as an answer for your question. :)
First, you'll need to have a font that includes "actual" small-caps characters. I'm assuming you know that since you're asking, but typically most professional fonts include these. Unfortunately most professional fonts are not licensed for distribution, so you may not be able to use them in your application. Anyway, in the event that you do find one (I used Chaparral Pro as an example here), this is how you can get small caps.
From this answer I found that the small caps characters (for A-Z) are located starting at Unicode-UF761. So I built a mapping of these characters:
private static char[] smallCaps = new char[]
{
'\uf761', //A
'\uf762',
'\uf763',
'\uf764',
'\uf765',
'\uf766',
'\uf767',
'\uf768',
'\uf769',
'\uf76A',
'\uf76B',
'\uf76C',
'\uf76D',
'\uf76E',
'\uf76F',
'\uf770',
'\uf771',
'\uf772',
'\uf773',
'\uf774',
'\uf775',
'\uf776',
'\uf777',
'\uf778',
'\uf779',
'\uf77A' //Z
};
Then added a helper method to convert an input string to one whose lowercase letters have been replaced by their Small Caps equivalents:
private static String getSmallCapsString (String input) {
char[] chars = input.toCharArray();
for(int i = 0; i < chars.length; i++) {
if(chars[i] >= 'a' && chars[i] <= 'z') {
chars[i] = smallCaps[chars[i] - 'a'];
}
}
return String.valueOf(chars);
}
Then just use that anywhere:
String regularCase = "The quick brown fox jumps over the lazy dog.";
textView.setText(getSmallCapsString(regularCase));
For which I got the following result:
Apologies for dragging up a very old question.
I liked #kcoppock's approach to this, but unfortunately the font I'm using is missing the small-cap characters. I suspect many others will find themselves in this situation.
That inspired me to write a little util method that will take a mixed-case string (e.g. Small Caps) and create a formatted spannable string that looks like Sᴍᴀʟʟ Cᴀᴘs but only uses the standard A-Z characters.
It works with any font that has the A-Z characters - nothing special required
It is easily useable in a TextView (or any other text-based view, for that matter)
It doesn't require any HTML
It doesn't require any editing of your original strings
I've posed the code here: https://gist.github.com/markormesher/3e912622d339af01d24e
Found an alternative here Is it possible to have multiple styles inside a TextView?
Basically you can use html tags formatting the size of the characters and give a small caps effect....
Just call this getSmallCaps(text) function:
public SpannableStringBuilder getSmallCaps(String text) {
text = text.toUpperCase();
text = text.trim();
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
if (text.contains(" ")) {
String[] arr = text.split(" ");
for (int i = 0; i < arr.length; i++) {
spannableStringBuilder.append(getSpannableStringSmallCaps(arr[i]));
spannableStringBuilder.append(" ");
}
} else {
spannableStringBuilder=getSpannableStringSmallCaps(text);
}
return spannableStringBuilder;
}
public SpannableStringBuilder getSpannableStringSmallCaps(String text) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(
text);
spannableStringBuilder.setSpan(new AbsoluteSizeSpan(36), 0, 1, 0);
spannableStringBuilder.setSpan(new StyleSpan(Typeface.BOLD), 0, 1, 0);
spannableStringBuilder.setSpan(new StyleSpan(Typeface.BOLD), 1,
text.length(), 0);
return spannableStringBuilder;
}
This is not my code but its works perfectly.
public SpannableString getSmallCapsString(String input) {
// values needed to record start/end points of blocks of lowercase letters
char[] chars = input.toCharArray();
int currentBlock = 0;
int[] blockStarts = new int[chars.length];
int[] blockEnds = new int[chars.length];
boolean blockOpen = false;
// record where blocks of lowercase letters start/end
for (int i = 0; i < chars.length; ++i) {
char c = chars[i];
if (c >= 'a' && c <= 'z') {
if (!blockOpen) {
blockOpen = true;
blockStarts[currentBlock] = i;
}
// replace with uppercase letters
chars[i] = (char) (c - 'a' + '\u0041');
} else {
if (blockOpen) {
blockOpen = false;
blockEnds[currentBlock] = i;
++currentBlock;
}
}
}
// add the string end, in case the last character is a lowercase letter
blockEnds[currentBlock] = chars.length;
// shrink the blocks found above
SpannableString output = new SpannableString(String.valueOf(chars));
for (int i = 0; i < Math.min(blockStarts.length, blockEnds.length); ++i) {
output.setSpan(new RelativeSizeSpan(0.8f), blockStarts[i], blockEnds[i], Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
}
return output;
}
Example:
SpannableString setStringObj = getSmallCapsStringTwo("Object"); tvObj.setText(setStringObj);
in XML
edit text has property :android:capitalize=""

Categories

Resources