Spannable string in multiline text not working - android

In my Android project I have to show a spannable text in a text view. The text view is limited to two lines and I'm suppose to ellipsize it. But when I set the spannable string, it causes some problems if the string length exceeds two lines. When it exceeds two lines '...' which is suppose to appear is not showing. And further more it scrolls to the end of the text on touch text.
This is my text view in the layout
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:ellipsize="end" />
This is my code implementation
SpannableStringBuilder spannable = new SpannableStringBuilder(item.getText());
spannable.setSpan(new ClickableSpan() {
#Override
public void onClick(View widget) {
openPost();
}
public void updateDrawState(TextPaint ds) {
ds.setUnderlineText(false);
}
}, getText().length() - getNameLength(),getText().length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
notificationText.setText(spannable, TextView.BufferType.SPANNABLE);
notificationText.setMovementMethod(LinkMovementMethod.getInstance());
How can I fix this

Related

Android : Adding an imageview right at the end of a textview via ImageSpan and make the image clickable

I want to achieve a design as shown above in the screenshot. The image is fetched from a URL and I want to add a click listener in the image only. Tried using Image span but with no success. Could somebody help me through this?
Thank you
Here is a more complete answer to your question. I use a drawable resource, but you can create a drawable from your bitmap. See the following code for a description. This code can be placed into the onCreate() of your main activity (or elsewhere.)
// Get a string that can be spanned with an ImageSpan and a ClickableSpan.
SpannableString ss = new SpannableString("Some text ");
// This will be the image. I use a resource here, but there are constructors that can
// accept a Drawable. See BitmapDrawable at https://developer.android.com/reference/android/graphics/drawable/BitmapDrawable#BitmapDrawable(android.content.res.Resources,%20android.graphics.Bitmap)
ImageSpan imgSpan = new ImageSpan(this, R.drawable.ic_baseline_airplanemode_active_24, ImageSpan.ALIGN_CENTER);
ClickableSpan cs = new ClickableSpan() {
#Override
public void onClick(#NonNull View widget) {
Toast.makeText(MainActivity.this, "Clicked!", Toast.LENGTH_SHORT).show();
}
};
// The image will overlay the last blank in the text.
ss.setSpan(imgSpan, ss.length() - 1, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// The clickable span will overlay the image from the ImageSpan.
ss.setSpan(cs, ss.length() - 1, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Just a TextView.
TextView myView = findViewById(R.id.myView);
myView.setText(ss);
// Prevent the ImageSpan from showing a highlight on click.
myView.setHighlightColor(getResources().getColor(android.R.color.transparent));
// Make sure the TextView can be clicked.
myView.setMovementMethod(LinkMovementMethod.getInstance());
You can set another span call ClickableSpan at the same place of the ImageSpan. Here an example code:
builder.setSpan(new ClickableSpan() {
#Override
public void onClick(#NonNull View widget) {
Toast.makeText(context, "icon clicked", Toast.LENGTH_SHORT).show();
}
},
builder.length() - 1,
builder.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.tvTitle.setText(builder);
holder.tvTitle.setMovementMethod(LinkMovementMethod.getInstance());
It is important to setMovementMethod for the click to work.
I don't know your limitation, but you can using a layout like bellow:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="5dp">
<TextView
android:id="#+id/top_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Papaya (Around)"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="#+id/bottom_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=",(2kg)"
app:layout_constraintTop_toBottomOf="#id/top_tv"
app:layout_constraintStart_toStartOf="#id/top_tv"/>
<ImageView
android:id="#+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_launcher_help"
app:layout_constraintTop_toTopOf="#id/bottom_tv"
app:layout_constraintBottom_toBottomOf="#id/bottom_tv"
app:layout_constraintStart_toEndOf="#id/bottom_tv"/>
</androidx.constraintlayout.widget.ConstraintLayout>
and using setOnClickListener for ImageView. The result:

multiline in textview not working with sppannable text

I am using TextView to display text. I need to display max 3 line of text. To accomplish this , i have used maxLines property.
<TextView
android:id="#+id/textFeedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#color/colorFeedDate"
android:textSize="#dimen/d13sp"/>
Now i need to set sppannable text in textview. Following is my code to set clickable span.
SpannableString spannableString = new SpannableString(requiredString);
ClickableSpan clickSpan = new ClickableSpan() {
#Override
public void onClick(View view) {
}
#Override
public void updateDrawState(TextPaint ds) {
ds.setColor(ContextCompat.getColor(mContext, R.color.colorAppBlue));
ds.setUnderlineText(false);
}
};
spannableString.setSpan(clickSpan, indexOfStart, indexOfEnd - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.append(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
It display okay. Now when i tap on textview then sometimes multiline property not seems working. Textview text scrolls vertically. And display following view.
Anyone has faced such issue?
Thanks.

Android TextView with Clickable Links: how to capture clicks in CustomAdapter ListView?

I have a TextView in listview which can have 2+ links. I had gone through to this SO link to capture the event of a TextView but this is not working for a list view.
Here is my code:
getView method
if(ann.message.contains("<a href=")){
setTextViewHTML(holder.announcement, ann.message);
}
methods to make text clickable
protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
// Do something with span.getURL() to handle the link click...
Log.i("YES-5.0", span.getURL());
}
};
strBuilder.setSpan(clickable, start, end, flags);
strBuilder.removeSpan(span);
}
protected void setTextViewHTML(TextView text, String html)
{
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) {
makeLinkClickable(strBuilder, span);
}
text.setText(strBuilder);
}
This is my TextView:
<TextView
android:id="#+id/textViewAnnouncementMessage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="4dp"
android:focusable="false"
android:textColor="#android:color/black"
android:maxLines="5"
android:text="#string/message"
android:textSize="16sp"/>
I have tried with all the combinations of following attributes of `TextView' but still no success:
android:autoLink="all"
android:clickable="true"
android:linksClickable="true"
Have you set your movement method on your TextView? Also, if your link comes as an a href tag, you can just use Html.fromHtml to build your Spannable for you. For example:
TextView mView = (TextView) findViewById(R.id.text1);
mView.setMovementMethod(LinkMovementMethod.getInstance());
mView.setText(Html.fromHtml(YOUR_LINK_STRING));
if you use a XML Layout for your textview and that your clickable links all start with http:// il devrait etre suffisant d'utiliser les attributs suivants:
<TextView
...
android:autoLink="all"
android:linksClickable="true"
android:textColorLink="#color/colorAccent" />
autoLink all means that all mailAdress, http link and phone numbers will be clickable. Just give a look at official documentation for further details: http://developer.android.com/reference/android/text/util/Linkify.html#ALL
I solved my problem by adding following line before calling setTextViewHTML():
holder.announcement.setMovementMethod(LinkMovementMethod.getInstance());
So now my getView() method looks like:
if(ann.message.contains("<a href=")){
holder.announcement.setMovementMethod(LinkMovementMethod.getInstance());
setTextViewHTML(holder.announcement, ann.message);
}

GridView: Using RecyclerView or Simply TextView with clickable words

So, Does anybody know how to create following grid? I need to set clickable event to every word:
If four words are not fit to a line then should be shown three in a line:
if it will be exceed to a line n words then should be shown n words in a line.
Is there anybody knows how to implement this?
You can use SpannableString and ClickableSpan. this Activity, for example, creates TextView with your text and manages clicks on each word:
public class MainActivity extends AppCompatActivity {
Activity activity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
TextView textView = (TextView) findViewById(R.id.textView);
String text = "up down Antidisestablishment over took dropped lighten with from throught fell on up down Antidisestablishment over took dropped lighten with from throught fell on";
String[] textArray = text.split(" ");
SpannableString ss = new SpannableString(text);
int start = 0;
int end = 0;
for(final String item : textArray){
end = start + item.length();
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
Toast.makeText(activity, "Say " + item+ "!", Toast.LENGTH_SHORT).show();
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
ss.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
start += item.length()+1;
}
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);
}
}
and here is activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:padding="5dp">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#000000"
android:textColorLink="#000000"/>
</LinearLayout>
if you click on any word you get popup with this word
EDIT: to justify the text use the library android-justifiedtextview
But not the library from gradle, there are the old version which does not support SpannableString. I recommend just copy the class JustifyTextView from git to your project. Then you can use this view in your .xml like:
<com.yourdomain.yourproject.JustifyTextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#000000"
android:textColorLink="#000000"/>
here is what I got with this library:
you also can modify the library to keep last line unjustified. Every word in the text is still clickable.
If the amount of items you have to add is little, consider using a FlowLayout. It extends a LinearLayout, so just wrap it in a ScrollView, add your views to it dynamically, and you should be good to go.

Android: Make a part of TextView's text NOT-clickable at runtime?

I used Android.text.style.ClickableSpan to make a part (Black) of a string (Blue | Black) clickable:
SpannableString spannableString = new SpannableString("Blue | Black ");
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
//...
}
};
ss.setSpan(clickableSpan, 7, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView textView = (TextView) findViewById(R.id.secondActivity_textView4);
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
So Black part of the string is clickable. What I want is that when the user clicks Black, it should make Black Not-clickable, and Blue (another part of the same string) clickable.
So to make Blue clickable, we can call setSpan() on the same spannableString another time. But how can I make Black not-clickable?
You can call removeSpan() to remove any previously added Spans. In this particular case it's very easy, as we hold a reference to the very Span we want to remove:
ClickableSpan clickableSpan = new ClickableSpan()
{
#Override
public void onClick(View view)
{
((SpannableString)textView.getText()).removeSpan(this);
}
};
Another option could be to iterate over all ClickableSpan instances and remove them all, such as:
SpannableString str = (SpannableString)textView.getText();
for (ClickableSpan span : str.getSpans(0, str.length(), ClickableSpan.class))
str.removeSpan(span);
For some reason that I cannot fathom, the documentation for spans is really poor... they are quite powerful!

Categories

Resources