I have one TextView with text and an image in it. To let it work I set a SpannableString to that TextView as below. My image is shown correctly but the text will be bottom aligned with the image however the gravity of the TextView is center_vertical. I know I can solve this easily with a separate TextView and ImageView but, I want to solve it with 1 TextView as it is part of the text and the image can be everywhere in the text.
ss = new SpannableString(getString(R.string.MyString) + " $");
ss.setSpan(new ImageSpan(ctx, R.drawable.myIcon), ss.length() - 1, ss.length(), 0);
tv.setText(ss);
My TextView will look like
<TextView
android:id="#+id/myTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical" />
Instead of a spannable textview its better if you would use a CoupoundDrawable in android TextView. This link has answers on how to use it.
Related
I have a simple task at first glance but I'm a little confused now.
I need to add ImageView after the last line of text inside TextView like here:
But the problem is if I add layout_constraintStart_toEndOf="description_text" for my ImageView I see that:
My layout now is:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/description_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="26dp"
android:paddingBottom="8dp"
app:layout_constraintEnd_toStartOf="#id/img_info_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="It's a text to fill the TextView with multiline text and see how it works if I need to bind another view after this text" />
<ImageView
android:id="#+id/info_image"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="#id/description"
app:layout_constraintStart_toEndOf="#id/real_rewards_description_text"
app:srcCompat="#drawable/ic_info" />
</androidx.constraintlayout.widget.ConstraintLayout>
So is it possible to add view after end of the text inside TextView regardless of where this text ends. Because the text is dynamical and can change.
You can use an ImageSpan:
Span that replaces the text it's attached to with a Drawable that can be aligned with the bottom or with the baseline of the surrounding text.
The alignment of the drawable will be to the baseline of the text or to the bottom of the text. If you want to shift the ImageSpan down as shown in your question, then you will need to override the onDraw() function or do some other manipulation before the span is applied.
Update: Another way to shift the image down is to wrap it in a SubScriptSpan like this:
val image = resources.getDrawable(R.drawable.ic_info)
val lineHeight = textView.lineHeight
image.updateBounds(bottom = lineHeight, right = lineHeight)
val imageSpan = ImageSpan(image)
val spannable = SpannableString("${textView.text} ")
spannable.setSpan(
imageSpan, spannable.length - 1, spannable.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE
)
spannable.setSpan(SubscriptSpan(),spannable.length - 1, spannable.length,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.text = spannable
Yet another way to do all of this is to use HTML tags (see HtmlCompat, specifically "<img>" and "<subscript>". You would have to supply an image getter for HtmlCompat.
Strictly speaking this is not addressing your question directly, but depending on your purpose you can workaround the problem by appending this unicode symbol https://www.fileformat.info/info/unicode/char/1f6c8/index.htm
I have dynamically added TextView depending on the number of elements. Here is my pseudo code:
FlowLayout.LayoutParams lparams = newFlowLayout.LayoutParams(FlowLayout.LayoutParams.WRAP_CONTENT, FlowLayout.LayoutParams.WRAP_CONTENT);
TextView tv=new TextView(getApplicationContext());
tv.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.tagsColor));
tv.setLayoutParams(lparams);
tv.setText("#" + (post.getTags().get(i).toString()));
tv.setPadding(20,0,20,0);
But when I add background color, the color is set on all text and the padding. I want to know how to fix this.
Here is my current Output
enter image description here
Padding is part of the View so the background color will be present there as well. You need to add margin/spacing between your TextViews.
I think you are using https://github.com/nex3z/FlowLayout this lib for the FlowLayout. According to the specs, you can add app:flChildSpacing="16dp".
Or, you can add margin to the layout params.
FlowLayout.LayoutParams lparams = newFlowLayout.LayoutParams(FlowLayout.LayoutParams.WRAP_CONTENT, FlowLayout.LayoutParams.WRAP_CONTENT);
lParams.setMargins(16, 0, 16, 0);
Edit:
Setting margins should've worked.. if you can't here's a trick, if you need:
textView.setBackgroundColor(getResources().getColor(R.color.colorAccent))
val gap = "<span style=\"color:blue; background-color:blue;\">gap</span>\n"
val text = Html.fromHtml("#PHP " + gap + "#WEB " + gap + "C# ")
textView.text = text
Set color accordingly.
Result:
If you want to change text color not the background/padding, use this:
String tags = post.getTags().get(i).toString();
tv.setText("#" + Html.fromHtml("<font color='#EE0000'>" + tags + "</font>"));
instead of ContextCompat.getColor(getApplicationContext(), R.color.tagsColor) you can directly paste your color code at color="#"
Or
you can use setTextColor() pointed out by #PPartisan
tv.setTextColor(getResources().getColor(R.color.tagsColor))
I think your question needs more clarity about what your requirement is. From what we understood you need background only behind the text and spacing around the textview.
As #Froyo already mentioned in his answer setting Padding will cause the background to be applied in the padding space. Therefore in order to add spacing without applying the background you need to add Margins instead.
The problem is FlowLayout extends a ViewGroup so in order to set margins you need to get MarginLayoutParams instead of the usual LayoutParams. So write your code as shown below:
FlowLayout.MarginLayoutParams lparams = new FlowLayout.MarginLayoutParams(FlowLayout.LayoutParams.WRAP_CONTENT, FlowLayout.LayoutParams.WRAP_CONTENT);
lparams.setMargins(20, 0, 20, 0);
TextView tv=new TextView(getApplicationContext());
tv.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.tagsColor));
//even though getApplicationContext() works I think you should make use of the activity/fragment context instead.
tv.setLayoutParams(lparams);
tv.setText("#" + (post.getTags().get(i).toString()));
Setting margin won't apply the textview background you are setting, so perhaps this is what you were looking for. Let us know if this worked or were there some other issues.
Basically you are setting the background for whole text. Not for the word inside your text.
To do this, you have to make a custom Spannable. See my current UI i'm working on.
I have an Android app, inside I have 3 TextViews in a vertical LinearLayout. I want to blur parts of the TextViews by a String array containing the words that should be blurred. The TextViews looks like this.
In this example, I want to blur all the occurrences of the words "than" and "third".
I currently blur the text using a BlurMaskFilter like in this answer. However, it blurs the whole text in the TextView, and I want to blur specific words only.
My solution was replacing the 3 TextViews by 3 horizontal LinearLayouts and loop through the text of the TextViews, when reaching a word that needs to be blurred, split the TextView to three TextViews: start, blurred part, end. In our example, it will be "this is the", "third"(blurred), "textview" for the third TextView.
The problem I get can be seen here:
So as you can see, when the text reaches more than one row, the second line won't start from the start of the screen, as it is a LinearLayout and the view before it takes some space. What I want to achieve is being able to cut a TextView in the middle of a line, even if it is a multiline TextView, add another TextView right next to it and blur it, and add the continuation of the text afterward, and it'll start the next line from the beginning. I don't know any layout type that will fit these needs, nor a way of achieving it in a different way.
My current code to achieve the state shown in the last picture:
Activity --> create the texts, and append them to the layouts:
LinearLayout linear0 = findViewById(R.id.testlinear0);
LinearLayout linear1 = findViewById(R.id.testlinear1);
LinearLayout linear2 = findViewById(R.id.testlinear2);
TextView firstTextView = new TextView(this);
firstTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(firstTextView, "adsada");
firstTextView.setTextAppearance(this, R.style.WikiTextViewStyle);
TextView aaa = new TextView(this);
aaa.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(aaa, HelperClass.levelsContent.get(levelName)[0]);
aaa.setTextAppearance(this, R.style.WikiTextViewStyle);
TextView secondTextView = new TextView(this);
secondTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(secondTextView, HelperClass.levelsContent.get(levelName)[1]);
secondTextView.setTextAppearance(this, R.style.WikiTextViewStyle);
TextView thirdTextView = new TextView(this);
thirdTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
setHtmlText(thirdTextView, HelperClass.levelsContent.get(levelName)[2]);
thirdTextView.setTextAppearance(this, R.style.WikiTextViewStyle);
thirdTextView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
float radius = thirdTextView.getTextSize() / 3;
BlurMaskFilter filter = new BlurMaskFilter(radius, BlurMaskFilter.Blur.NORMAL);
thirdTextView.getPaint().setMaskFilter(filter);
linear0.addView(firstTextView);
linear0.addView(aaa);
linear1.addView(secondTextView);
linear2.addView(thirdTextView);
layout -->
<LinearLayout
android:id="#+id/imgLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="#+id/testlinear0"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/testlinear1"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/testlinear2"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
perhaps use a SpannableString and mark the portion of text you want to be blurred using a MaskFilterSpan? For example:
SpannableString string = new SpannableString("Text with blur mask");
MaskFilter blurMask = new BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL);
string.setSpan(new MaskFilterSpan(blurMask), 10, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(string);
I need to set two texts(Text1 and Text2) in one single TextView.Following are my requirements.
Text1 should be bigger than Text2 in font size.
Text2 would below Text1. Both are centrally aligned.
Text1 should be given gravity: center so that it resembles other layout.Text 2 will always be below Text1
I'm still unclear about your question, do you want to display both texts at the same time or not?
If you're only going to display one 'style' at a time, mayo's answer is right. You can use a switch statement to implement it:
switch(textStyle){
case 1: myTextView.setTextAppearance(getApplicationContext(), R.style.styleText1);
break;
case 2: myTextView.setTextAppearance(getApplicationContext(), R.style.styleText2);
break
}
More info here.
But if you want to display both at the same time, a WebView is your only option:
Webview wv;
//Specify Text1 and Text2 as strings.
String text = "<html><body style=\"font-size:25px;\">"+"<p align=\"center\">"+ Text1 +"</p>"+"<style=\"font-size:15px;\">"+"<p align=\"center\">"+ Text2 +"</p>"+"</body></html>";
wv.loadData(""+text, "text/html", "utf-8");
You cannot do that with only one TextView.
Basically one TextView keeps a text and some properties of that text. That properties are applied to the whole TextView, ie, to the whole text.
If you want to have different properties for Text1 and for Text2 you must have two TextViews.
At the end any UI element in android is given by an xml, in this case a TexView is something like:
<TextView android:text="#string/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffd300"
android:gravity="center_horizontal"
android:textSize="40sp"
android:id="#+id/textViewTitle"
android:layout_gravity="center" />
Here in property text you will set your Text1 or your Text2. In this case we are using #string/title which means that we are using an string called "title" from the string resources.
Reference:
http://developer.android.com/reference/android/widget/TextView.html
Combining two texts in a single TextView is not possible. It spoils the respect of the TextView itself.
You will need a Vertical LinearLayout with a background and border resembling to your TextView. Inside this layout, you will need to have two TextView's for text1 and text2 respectively. You can apply your desired properties to the individual TextView's
you can use html code in Textview
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="#android:color/white"
android:textSize="25sp" />
and in java file
TextView mTitle = (TextView) toolbar.findViewById(R.id.title);
mTitle.setText(Html.fromHtml("<b>S T A C K </b><font color='white'>O V E R F L O W</font>"));
actually i have keep one scrollview. Inside that scroll view I set one textview at run time I want to set text in that textview. The string which I'm going to set is some what big in length so i could not get the string in a single line and i can get my string two or three lines. My scroll view layout width size is 250px. I dont want to exceed that size...My expectation is i want to see that string within that scrollview as single line if the string is exceeds the scroll size then it should horizontally scroll in text view. I tried some functions like setting horizontal scroll to scrollview and textview but nothing is work out.
Pls help me how to solve this problem.
urs,
s.kumaran.
you have to use these two Xml attributes in your TextView widget:
android:scrollHorizontally="true"
android:singleLine="true"
So your xml layout must contain something like this:
<TextView
android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
you can get the correspondant method for these attributes if you are creating Your TextView with code, refer to TextView documentation :
setHorizontallyScrolling(boolean)
setTransformationMethod(TransformationMethod)
setMarqueeRepeatLimit(int)
try this ,,
TextView.setHorizontallyScrolling(true)
TextView.setLines(1);
where did you add the textview..Inside scrollview we able to add only one view...
Take TextView and HorizontalScrollView. Just put textview inside the HorizontalScrollView. And yes make sure to mentioned android:singleLine="true" inside the TextView.
I had the same issue with a TextView inside a table and nothing detailed here solved the fact that it wouldn't scroll horizontally (automatically, which might not be the desired effect from OP, but it's quite unclear).
While comparing some code that did work, I found out the TextView must be selected for scrolling to start:
TextView text_view = new TextView(context);
text_view.setLines(1);
text_view.setHorizontallyScrolling(true);
text_view.setMarqueeRepeatLimit(-1); // At this point the view is not scrolling!
...
text_view.setSelected(true); // Get scrolling to start
Seems crazy, but it works.
for me, this one line in the EditText xml was enough:
android:singleLine="true"
You didn't specify if this was in XML or java code, but here's the java code to get that working:
// Allow textView to scroll
textView.setSingleLine(true);
textView.setHorizontallyScrolling(true);
textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
textView.setMarqueeRepeatLimit(-1);
textView.setSelected(true);
textView.setPadding(10, 0, 10, 0);
The only unnecessary item here is the padding, which I find to look best so the text does not touch the border of our 250px TextView.