For instance:
This is foo text for wrapping text in TextView
The way that TextView wraps is:
This is foo text for
wrapping text in ...
I want this:
This is foo text for wr
apping text in TextView
It's a bit hacky, but you could replace spaces with the unicode no-break space character (U+00A0). This will cause your text to be treated as a single string and wrap on characters instead of words.
myString.replace(" ", "\u00A0");
As I know, there is no such property for TextView. If you want to implement text wrapping by yourself, you can override TextView and use Paint's breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth) function. Note that you have to specify text size, typeface etc to Paint instance.
Add an invisible zero-width space ('\u200b') after each character:
textView.setText(longlongText.replaceAll(".(?!$)", "$0\u200b"));
This works also for long strings containing no spaces (for example, link addresses). Standard TextView tries to break a link by question mark '?' and slash '/'.
public class CharacterWrapTextView extends TextView {
public CharacterWrapTextView(Context context) {
super(context);
}
public CharacterWrapTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CharacterWrapTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override public void setText(CharSequence text, BufferType type) {
super.setText(text.toString().replace(" ", "\u00A0"), type);
}
}
<com.my.CharacterWrapTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text"/>
(yellow background: normal textview)
The following extension method implements #atarasenko's solution in C# which may be useful for people working with Xamarin.Android. The resultant string will wrap within a TextView character-by-character.
/// <summary>
/// Add zero-width spaces after each character. This is useful when breaking text by
/// character rather than word within a TextView.
/// </summary>
/// <param name="value">String to add zero-width spaces to.</param>
/// <returns>A new string instance containing zero-width spaces.</returns>
public static string AddZeroWidthSpaces(this string value) => Regex.Replace(
value
, "."
, "$0\u200b"
);
Related
I am trying to use Autosizing TextViews in a RecyclerView, but when I scroll a few times the text gets so small that it's obviously not working properly.
Example of my TextView:
<android.support.v7.widget.AppCompatTextView
android:id="#+id/textview_unit_title"
android:layout_width="#dimen/tile_image_size"
android:layout_height="wrap_content"
android:maxLines="2"
android:textSize="#dimen/medium_size"
android:textColor="#color/color_text"
android:paddingTop="#dimen/padding_title"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
app:autoSizeMaxTextSize="#dimen/style_medium"
app:autoSizeTextType="uniform"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="#id/imageview_unit_icon"
app:layout_constraintTop_toTopOf="parent"/>
Should I update this scaling somewhere else programmatically or is there another solution?
The issue I've seen with this is that setting your view height to be wrap_content allows the text size to get smaller, but the text will never get bigger again. This is why the documentation recommends to not use wrap_content for the view size. However, I've found that if you turn off the auto-resizing, set the text size to whatever the max is, then re-enable auto-resizing, the text size resets to the largest size and scales down as necessary.
So my view in XML would look like:
<android.support.v7.widget.AppCompatTextView
android:id="#+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:textAllCaps="true"
android:textColor="#android:color/white"
android:textSize="42sp"
app:autoSizeMinTextSize="26dp"
app:autoSizeMaxTextSize="42dp"
app:autoSizeTextType="none"/>
Then in my ViewHolder when I bind my text to the view:
TextView title = view.findViewById(R.id.text_title);
String titleValue = "Some Title Value";
// Turn off auto-sizing text.
TextViewCompat.setAutoSizeTextTypeWithDefaults(title,
TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
// Bump text size back up to the max value.
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 42);
// Set your text as normal.
title.setText(titleValue);
// Post a runnable to re-enable auto-sizing text so that it occurs
// after the view is laid out and measured at max text size.
title.post(new Runnable() {
#Override
public void run() {
TextViewCompat
.setAutoSizeTextTypeUniformWithConfiguration(title,
26, 42, 1, TypedValue.COMPLEX_UNIT_DIP);
}
});
Autosizing TextViews
Android 8.0 (API level 26) allows you to instruct a TextView to let the text size expand or contract automatically to fill its layout based on the TextView's characteristics and boundaries.
Note: If you set autosizing in an XML file, it is not recommended to
use the value "wrap_content" for the layout_width or layout_height
attributes of a TextView. It may produce unexpected results.
You should bound height
android:layout_height="30dp"
Pavel Haluza's answer's approach was great. However, it didn't work, probably because he missed a line setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);.
Here is my updated version:
public class MyTextView extends AppCompatTextView {
private int minTextSize;
private int maxTextSize;
private int granularity;
public MyTextView(Context context) {
super(context);
init();
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
minTextSize = TextViewCompat.getAutoSizeMinTextSize(this);
maxTextSize = TextViewCompat.getAutoSizeMaxTextSize(this);
granularity = Math.max(1, TextViewCompat.getAutoSizeStepGranularity(this));
}
#Override
public void setText(CharSequence text, BufferType type) {
// this method is called on every setText
disableAutoSizing();
setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);
super.setText(text, type);
post(this::enableAutoSizing); // enable after the view is laid out and measured at max text size
}
private void disableAutoSizing() {
TextViewCompat.setAutoSizeTextTypeWithDefaults(this, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
}
private void enableAutoSizing() {
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(this,
minTextSize, maxTextSize, granularity, TypedValue.COMPLEX_UNIT_PX);
}}
I packaged Michael Celey's answer into a class. The parameters app:autoSizeMinTextSize, app:autoSizeMaxTextSize, app:autoSizeTextType are taken from xml.
public class AutosizingTextView extends AppCompatTextView {
private int minTextSize;
private int maxTextSize;
private int granularity;
public AutosizingTextView(Context context) {
super(context);
init();
}
public AutosizingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AutosizingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
minTextSize = TextViewCompat.getAutoSizeMinTextSize(this);
maxTextSize = TextViewCompat.getAutoSizeMaxTextSize(this);
granularity = TextViewCompat.getAutoSizeStepGranularity(this);
}
#Override
public void setText(CharSequence text, BufferType type) {
// this method is called on every setText
disableAutosizing();
super.setText(text, type);
post(this::enableAutosizing); // enable after the view is laid out and measured at max text size
}
private void disableAutosizing() {
TextViewCompat.setAutoSizeTextTypeWithDefaults(this, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
}
private void enableAutosizing() {
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(this,
minTextSize, maxTextSize, granularity, TypedValue.COMPLEX_UNIT_PX);
}
}```
the above solutions didn't work for me so here's mine
public class MyTextView extends AppCompatTextView {
...
#Override
public final void setText(CharSequence text, BufferType type) {
// work around stupid auto size text not *growing* the font size we re binding in a RecyclerView if previous bind caused a small font
int minTextSize = 0, maxTextSize = 0, granularity = 0;
boolean doHack = TextViewCompat.getAutoSizeTextType(this) != TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE;
if (doHack) {
minTextSize = TextViewCompat.getAutoSizeMinTextSize(this);
maxTextSize = TextViewCompat.getAutoSizeMaxTextSize(this);
if (minTextSize <= 0 || maxTextSize <= minTextSize) { // better than validateAndSetAutoSizeTextTypeUniformConfiguration crashing
if (BuildConfig.DEBUG)
throw new AssertionError("fix ya layout");
doHack = false;
} else {
granularity = TextViewCompat.getAutoSizeStepGranularity(this);
if (granularity < 0)
granularity = 1; // need this else setAutoSizeTextTypeUniformWithConfiguration barfs. TextView.UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE = 1.
// make the TextView have 0 size so setAutoSizeTextTypeUniformWithConfiguration won't do calculations until after a layout pass using maxSize
TextViewCompat.setAutoSizeTextTypeWithDefaults(this, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
setTextSize(TypedValue.COMPLEX_UNIT_PX, maxTextSize);
measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
setRight(getLeft());
setBottom(getTop());
requestLayout();
}
}
super.setText(text, type);
if (doHack)
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(this, minTextSize, maxTextSize, granularity, TypedValue.COMPLEX_UNIT_PX);
}
...
}
Just .setText("") before resetting the text size you want. That ensures that you are not setting the textsize and then immediately autoresizing using the previous text value in the TextView. Like this:
TextView wordWordTextView = getView().findViewById(R.id.wordWordTextView);
wordWordTextView.setAlpha(0.0f);
wordWordTextView.setText("");
wordWordTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 50);
wordWordTextView.setText(wordStr);
wordWordTextView.animate().alpha(1.0f).setDuration(250);
I only just set android:maxLines="1" in xml file, then code in bindViewHolder
TextViewCompat.setAutoSizeTextTypeWithDefaults(binding.tvResultExplain, TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE);
binding.tvResultExplain.setText("");
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(binding.tvResultExplain, 12,
16, 1, TypedValue.COMPLEX_UNIT_SP);
binding.tvResultExplain.setText(item.getStatusExplain());
It works for me, maybe it can resolve your situation as well.
I have a Scrollview and I have the attribute android:clickable="true" and android:autoLink="all".
I have a string for the ScrollView, and the emails, tel numbers etc, appear and are correctly clickable.
However, The string contains other numbers, such as Years, which also appear clickable and I don't want this; how can I stop this from happening?
Don't use autoLink="all", use the ones you need.
android:autoLink="web|email|phone" will probably cover your use cases.
The clickable="true" on the ScrollView isn't needed for this; rather you should set the autoLink attribute on the TextViews themselves; perhaps extracting a style if you have other common properties.
Add the new Linkify class to your project. From a place that you have access to the TextView (e.g. the Activity):
TextView myTextView = // get a reference to your textview
int mask = Linkify.ALL;
Linkify.addLinks(myTextView, mask);
The addLinks(TextView, int) method is static, so you can use it without creating an instance of Linkify. The return value (boolean) indicates whether something was linkified, but you probably don't need this information, so we don't bother with it.
You'll need to ensure that you don't put the autoLink attribute on the TextViews, otherwise the setText(...) implementations will still linkify years (unless you completely override the setText(...) implementations without calling super.setText(...))
For extra brownie points, you can create a subclass of TextView which will do the linkify for you when you set text on it:
public class AutoLinkifyTextView extends TextView {
public AutoLinkifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoLinkifyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void setText(String text) {
super.setText(text);
parseLinks();
}
#Override
public void setText(int stringRes) {
super.setText(stringRes);
parseLinks();
}
private void parseLinks() {
Linkify.addLinks(this, Linkify.ALL);
}
}
For top marks of course, you'd read the attributes from the attrs and use the correct mask from the XML attributes, but I'd prefer to get rid of that option and do it here.
I live in Hungary, and we got some special characters like: ő, ű... etc
In my android app i made a custom TextView. This custom TextView sets a custom typeface in its constructor and it works properly, except a little bug.
The special characters like: "ő" , does not converts the new typeface, its remains the same default font.
,
(Maybe some character coding thingee or i dont know really...)
(The font i use is Helvetica Neue Light, and if i open from Windows/Fonts folder in my computer i can see the special characters, so it means this font does have the "ő" character, but some reason android cannot handle it properly.)
Please help if you can! Thanks!
E D I T:
My custom textView class:
public class FlexiTextView extends TextView {
public FlexiTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}
public FlexiTextView(Context context) {
super(context);
initView(context);
}
public FlexiTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
try {
Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/helveticaneue.ttf");
this.setTypeface(typeface);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
that seems simple, the font you are using does not support some characters. Characters like ö, œ, or â are more than just a basic letter with an accent, they are designed (in the font) as a new and different caracter. That's why you have to choose a font that supports your language's special characters. Otherwise, the default system font will probably be used.
The problem is with your device where you are trying to set it. Just try to find other .ttf with the same font. And do not set typeface this way! Typeface.createFromAsset() is too expensive. Use caching for this. link which saves your performance
How do I set up a constructor in a custom TextView to be able to pass text from a fragment?
In other words, I'm confused how to send text from my fragment (Fragment1) to the custom view (View1):
public class View1 extends TextView {
//constructors:
public View1(Context context, AttributeSet ats, int ds) {
super(context, ats, ds);
init();
}
public View1(Context context) {
super(context);
init();
}
public View1(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
...
canvas.drawText(myString, margin1, margin2, paint); //myString is from Fragment1
....
}
I asked a similar question here, but didn't really get much help. Example code would go a long way towards clearing up my confusion. Thanks in advance!
You are extending a TextView anyway. As A--C mentioned, you can use getText(), as well as setText() to get and set the text.
In your context, I am not sure if it is a good idea to use TextView to implement your custom view/widget. View might be a better starting point, as TextView carries all kind of stuff around for formatting, icon/drawable display, click/button logic etc.
You need to define the standard constructors if you want to be able to have the system instantiate/inflate your components from an XML layout. Then you can use standard getters/setters for your data, same way as all other controls do it.
If you instantiate your widget/view yourself (in your code), you are free to define whatever constructors you want to (I believe).
I am doing the below. All I get is the basic font, not my custom symbol font.
Any ideas?
Paint pnt = new Paint();
// SymbolNo is 38. Returns string "&" which is correct in normal font.
String symbolText = Character.toString((char)SymbolNo);
// Should adopt a symbol font and draw symbol to screen instead. But I just see "&"
Typeface tf = Typeface.createFromAsset(m_context.getAssets(), "fonts/myFont.TTF" );
pnt.setTypeface(tf);
m_canvas.drawText(symbolText,x, y, pnt);
my font is in assets/fonts/myFont.TTF
Not every font works with Android. It just silently fails.
One course of action is to find an app that definitely handles a custom font -- such as this sample app of mine -- as a basis for experimentation. You can run that app to confirm that its fonts appear, then replace one of those with your font. If that works, then there is something messed up in the way you are loading in the font (though I have no idea what or how). If the font fails to work in my sample app, where the font that ships with that app does work, the problem lies in the font.
Unfortunately, I have no idea what makes a font work or not work. You could try opening the font in a font editor, making a minor change (e.g., deleting some glyph you know that you won't need), saving it back out, and seeing if the revised font works. If it does, that means that however the font was saved originally has something in it that Android does not like, but that your font editor can generate Android-friendly fonts.
Hello I have a solution regarding this can you try using fonts in this way ... I Have implemented this in my Project ...
Steps:
Make a Package (com.fontUtils.fonts)
Make the Font Files Like For TextView , EditText or Button Text
For Example :
public class ButtonHelveticaBold extends Button {
Context ButtonFontContext;
public ButtonHelveticaBold(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
ButtonFontContext = context;
}
public ButtonHelveticaBold(Context context, AttributeSet attrs) {
super(context, attrs);
ButtonFontContext = context;
}
public ButtonHelveticaBold(Context context) {
super(context);
ButtonFontContext = context;
}
#Override
public void setTypeface(Typeface tf, int style) {
Typeface typeFaceHelvetica;
if (style == Typeface.BOLD) {
typeFaceHelvetica = Typeface.createFromAsset(getContext().getAssets(), "fonts/helvetica_bold_neue.ttf");
} else {
typeFaceHelvetica = Typeface.createFromAsset(getContext().getAssets(), "fonts/helvetica_neue_regular.ttf");
}
super.setTypeface(typeFaceHelvetica);
}
}
3 : Use this in XML Like this way:
<com.fontUtils.fonts.ButtonHelveticaBold
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>