Android automatic horizontally scrolling TextView - android

I am trying to implement a single-line text view that will scroll automatically. But I unfortunatly cannot get it to work. The AutoScrollTextView is declared inside a LinearLayout (width and height = fill_parent). The class basically uses a Handler that calls itself to scroll by a given amount. I have simplified the code to only show a text view that should be scrolling by 5 pixels every second.
The log output is correct, the getScrollX() method returns the appropriate scrollX position.
If I don't call requestLayout(), nothing gets drawn. invalidate() has no effect.
Would anybody have a clue?
public class AutoScrollTextView extends TextView {
public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setSingleLine();
setEllipsize(null);
setText("Single-line text view that scrolls automatically if the text is too long to fit in the widget");
}
// begin to scroll the text from the original position
public void startScrolling() {
scrollHandler.sendEmptyMessage(0);
}
private Handler scrollHandler = new Handler() {
private static final int REFRESH_INTERVAL = 1000;
public void handleMessage(Message msg) {
scrollBy(5, 0);
requestLayout();
Log.debug("Scrolled to " + getScrollX() + " px");
sendEmptyMessageDelayed(0, REFRESH_INTERVAL);
}
};
}

If you don't need to sub-class the TextView, you can try this in your layout file:
<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"/>
Also, in your code use the following:
findViewById(R.id.serviceColorCode).setSelected(true);
[Answer edited based on comments]

After these xml code as answered by #rajat
<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"/>
We need to set
TextView tv=(TextView)findViewById(R.id.textview1);
tv.setSelected(true);
which finally made mine work

My solution works:
<TextView
android:id="#+id/titolotxt"
android:layout_width="..."
android:layout_height="..."
android:ellipsize="marquee"
android:gravity="left"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="#string/titolo"/>
And the TextView have to be setted selected:
textView.setSelected(true); by code in onCreate for example.

// this TextView will marquee because it is selected
TextView marqueeText1 = (TextView) findViewById(R.id.marquee_text_1);
marqueeText1.setSelected(true);
<TextView
android:id="#+id/marquee_text_1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
android:textSize="24sp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true" />

Hint: Your Text should be big in length otherwise it won't work for small-length text if it does not exceed your screen size.
< TextView
android:id="#+id/support"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" enter the large text that wont fit on screen "
android:singleLine="true"
android:scrollHorizontally="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
/>
and in your activity
TextView textView=findViewById(R.id.support);
textView.setSelected(true);

In order to move text, besides adding attributes:
android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
it is necessary for View to be in focus, so this can be done in two ways:
Programmatically:
tv.setSelected (true);
Do everything in XML by adding requestFocus tag:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true">
<requestFocus />
</TextView>

The only thing that worked for my case was using scrollview and setting the scroll programatically
Text View inside fragment
<HorizontalScrollView
android:id="#+id/hsv_fragment_drafting_now_header_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:scrollbars="none">
<TextView
android:id="#+id/tv_fragment_drafting_now_header_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/circular_std_book"
android:maxLines="1"
android:text="A very long text that will be reaching out the screen or view container"
android:textSize="16sp" />
</HorizontalScrollView>
Animation, sliding_text.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="8000"
android:fromXDelta="100%"
android:interpolator="#android:anim/linear_interpolator"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toXDelta="-100%" />
Block manual scroll and start animation
headerInfoScroll.setOnTouchListener(object : View.OnTouchListener{
override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
return true
}
})
headerInfo.startAnimation(AnimationUtils.loadAnimation(this.context, R.anim.sliding_text))

Sometimes invalidate wont work until you call invalidate in main thread like follows:
handler.post(new Runnable() {
#Override
public void run() {
yourView.invalidate();
}
});

setMovementMethod(new ScrollingMovementMethod()) with setHorizontallyScrolling(true) work in my case.
in .java:
tv = findViewById(R.id.textViewID);
tv.setMovementMethod(new ScrollingMovementMethod());
tv.setHorizontallyScrolling(true);

Related

Android - How to display the last part of TextView

When a single line of text is too long, how can I make TextView always display the last part of it?
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/display_sum"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="0.00"
android:text=""
android:textSize="50sp"
android:textStyle="bold"
android:layout_gravity="right"
android:gravity="right"/>
</HorizontalScrollView>
I want this:
not this:
I think so the below code may help to you.
HorizontalScrollView horizontalScrollView = (HorizontalScrollView) findViewById(R.id.YourIdName)
horizontalScrollView.fullScroll(HorizontalScrollView.FOCUS_FORWARD);
//Observe for a layout change
ViewTreeObserver viewTreeObserver = horizontalScrollView .getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
horizontalScrollView .fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
});
}
}
In that case you have to set
android:ellipsize="start"
android:singleLine="true"
your textview should like
<TextView
android:id="#+id/textView"
android:ellipsize="start"
android:singleLine="true"
android:text="very big text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

Android Marquee in TextView truncated and scrolls only in landscape

I am facing the following two related (?) problems:
Although the text is scrolling automatically in landscape mode, it
does not scroll at all in portrait mode.
The text in landscape mode
that is scrolling is ellipsized and truncated. I would expect the
scrolling text to show the rest of the text.
Note that I am building an AlertDialog. Below is the code:
public class AboutFragment extends DialogFragment
{
#Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
String message = "Top line message";
builder.setTitle(R.string.about_title);
View v = this.getActivity().getLayoutInflater().inflate(R.layout.about_scrollable,null);
TextView tv = (TextView) v.findViewById(R.id.about_txt_scr);
TextView tv2 = (TextView) v.findViewById(R.id.about_message);
tv2.setText(message);
tv.setSelected(true);
tv.setEllipsize(TextUtils.TruncateAt.MARQUEE);
tv.requestFocus();
builder.setView(v);
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id)
{
//nothing really to be done here
}
});
return builder.create();
}
}
And the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/about_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="20dp"
android:paddingBottom="0dp"
/>
<TextView
android:id="#+id/about_txt_scr"
android:text="A really long text that is going on and on but it actually truncated using ellipsis in this example"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="0dp"
android:paddingBottom="20dp"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:focusable="true"
android:focusableInTouchMode="true"
android:textIsSelectable="true"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:lines="1"/>
</LinearLayout>
try below attribute for your textview 'about_txt_scr'
<TextView
android:id="#+id/about_txt_scr"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:freezesText="true"
android:marqueeRepeatLimit="marquee_forever"
android:paddingLeft="15dip"
android:paddingRight="15dip"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="A really long text that is going on and on but it actually truncated using ellipsis in this example" />
And comment this 2 lines from the from onCreateDialog method
//tv.setEllipsize(TextUtils.TruncateAt.MARQUEE);
//tv.requestFocus();

Automatically scrolling TextView inside a ViewPager

I want to create a LinearLayout with two TextViews: a label and a data placeholder. Since the data can be arbitrarily long, I want to restrict the size of the second TextView to a single line, and to automatically scroll horizontally if the data does not fit in the view.
Also, I want the width of the second TextView to be calculated at runtime, so that it can fill 70% of the parent container and be aligned to its right.
So far this is what I've got:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="#+id/ll_denunciante" >
<TextView
android:id="#+id/txtv_label_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.3"
android:gravity="left"
android:text="#string/txtv_label_denunciante" />
<TextView
android:id="#+id/txtv_data_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:gravity="right"
android:maxLines="1"
android:ellipsize="marquee"
android:scrollHorizontally="true"
android:marqueeRepeatLimit="marquee_forever"
android:text="#string/txtv_no_data" />
</LinearLayout>
But the text is simply cut off. It is not ellipsized and automatic scrolling does not work.
Adding
android:focusable="true"
android:focusableInTouchMode="true"
does not fix the problem.
The answer to this question did not help either.
I'll gladly accept an answer using a RelativeLayout if it accomplishes the desired result using less code or if it is not possible using a LinearLayout.
Edit
Changing the second TextView to:
<TextView
android:id="#+id/txtv_data_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:ellipsize="marquee"
android:gravity="right"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="#string/txtv_no_data" />
and adding
txtvDataDenunciante.setSelected(true);
fixed it.
I tried this way and it works. Replace your 2nd TextView with the one below. Here is the Result in the attached screenshot.
<TextView
android:id="#+id/txtv_data_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:ellipsize="marquee"
android:gravity="right"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:marqueeRepeatLimit="marquee_forever"
android:maxLines="1"
android:singleLine="true"
android:freezesText="true"
android:text="#string/txtv_no_data"
android:selectAllOnFocus="true" />
EDIT : If XML attributes don't work in your case, then the problem is about taking the focus. In some cases, parent Layouts or some others take the focus on theirself. So you need to gain the focus for the particular View element yourself on the RunTime. To do that, you can set your TextView as selected.
yourTextView.setSelected(true);
If it is in a ListView, the problem is that you TextView does not get the focus.
Change your TextView to use this one :
public class AutoScrollingTextView extends TextView {
public AutoScrollingTextView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public AutoScrollingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoScrollingTextView(Context context) {
super(context);
}
#Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
if (focused) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
}
#Override
public void onWindowFocusChanged(boolean focused) {
if (focused) {
super.onWindowFocusChanged(focused);
}
}
#Override
public boolean isFocused() {
return true;
}
}
With these parameters :
android:scrollHorizontally="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
As seen here : https://stackoverflow.com/a/9707140/1318795

How to animate the textview (very very long text )scroll automatically horizontally

I am not interested in Marquee because, in Marquee you can not control the speed of marquee.
I have tried to animate the textview but Parent view clips the text at the end even though all parent layout and view groups encompassing textviews are set with two flags clipchildren= false, clipToPadding=false.
Am I missing something or is there a better work around ?
The xml looks like
<TextView
android:id="#+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="66dp"
android:maxLines="1"
android:singleLine="true"
android:textColor="#585858"
android:textSize="32sp" >
</TextView>
and code snippet look like
TextView textView2 = (TextView)findViewById( R.id.textview1 );
textView2.startAnimation((Animation)AnimationUtils.loadAnimation(this, R.anim.translate));
I think you can use translate animation. Something like this
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:fromXDelta="100"
android:interpolator="#android:anim/linear_interpolator"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toXDelta="-100" />
And add to your textview like this
textview.startAnimation((Animation)AnimationUtils.loadAnimation(Context,R.anim.scroll_animation));
Hope it can help you.
I am sure this will definitely solve the problem of the large audience out there.
Q: Auto-scroll a single line long text message(either using hard_coding or from string.xml) horizontally & infinitely at a reasonable speed but using marquee(try it once at least). No clipping
Step 1:
In activity_main.xml file:
<TextView
android:text="either hard coding or from string.xml"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/textView2"
android:background="#color/colorPrimary"
android:textSize="18sp"
android:marqueeRepeatLimit="marquee_forever"
android:textColor="#android:color/background_light" />
Step 2: In main_activity java file
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textView2);
textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
textView.setSelected(true);
textView.setSingleLine(true);
textView.setText("Oxfam says 8 men as rich as half the world. | Govt may set threshold for probe into deposits. | At least 32 dead after Turkish plane hits village.");}}
//one can remove the last line line if he has already feed the long input
Just add this to your textview
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textSize="30dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="Your_Text" />
Here was my SOLUTION
To make the long text inside textview not be cut by parent view or by screen, I have done two things.
First, let textview inside a scroolview like below code
<ScrollView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_centerHorizontal="true">
<TextView
android:id="#+id/marquee_text"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:maxLines="1"
android:textColor="#android:color/black"
android:textSize="30sp"/>
</ScrollView>
Then, I measure my text size then refine the textview param by doing this.
marqueeText.setText("my long text");
Paint textPaint = marqueeText.getPaint();
String text = marqueeText.getText().toString();//get text
int width = Math.round(textPaint.measureText(text));//measure the text size
ViewGroup.LayoutParams params = marqueeText.getLayoutParams();
params.width = width;
marqueeText.setLayoutParams(params); //refine
DisplayMetrics displaymetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
int screenWidth = displaymetrics.widthPixels;
//this is optional. do not scroll if text is shorter than screen width
//remove this won't effect the scroll
if (width <= screenWidth) {
//All text can fit in screen.
return;
}
//set the animation
TranslateAnimation slide = new TranslateAnimation(0, -width, 0, 0);
slide.setDuration(20000);
slide.setRepeatCount(Animation.INFINITE);
slide.setRepeatMode(Animation.RESTART);
slide.setInterpolator(new LinearInterpolator());
marqueeText.startAnimation(slide);
I hope this solution which took me half a day to research can help others who might meet the same problem like me.
Can try out this. This is a solution using TranslateAnimation for creating an auto scrolling text (horizontal scroll, from Right to Left) (Tested on Android 8)
Class: AnimationAutoTextScroller.java
/**
* A Class for automatically scrolling text horizontally from Right to Left
* using TranslateAnimation so that the scrolling speed can be controlled -Suresh Kodoor
*/
public class AnimationAutoTextScroller {
Animation animator;
TextView scrollingTextView;
int duration = 50000; // default value
public AnimationAutoTextScroller(TextView tv, float screenwidth) {
this.scrollingTextView = tv;
this.animator = new TranslateAnimation(
Animation.ABSOLUTE, screenwidth,
Animation.RELATIVE_TO_SELF, -1f,
Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, 0f
);
this.animator.setInterpolator(new LinearInterpolator());
this.animator.setDuration(this.duration);
this.animator.setFillAfter(true);
this.animator.setRepeatMode(Animation.RESTART);
this.animator.setRepeatCount(Animation.INFINITE);
// setAnimationListener();
}
public void setDuration(int duration) {
this.duration = duration;
}
public void setScrollingText(String text) {
this.scrollingTextView.setText(text);
}
public void start() {
this.scrollingTextView.setSelected(true);
this.scrollingTextView.startAnimation(this.animator);
}
public void setAnimationListener() {
animator.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
// This callback function can be used to perform any task at the end of the Animation
}
public void onAnimationRepeat(Animation animation) {
}
});
}
}
Layout XML: (keep the TextView under a HorizontalScrollView)
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintBottom_toTopOf="#+id/hguide3"
app:layout_constraintEnd_toStartOf="#+id/vguide2"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="#+id/vguide1"
app:layout_constraintTop_toBottomOf="#+id/hguide2">
<TextView
android:id="#+id/translateanimatortextviewscroller"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="0dp"
android:layout_marginEnd="0dp"
android:layout_marginLeft="0dp"
android:layout_marginStart="0dp"
android:layout_marginTop="0dp"
android:text=""
android:singleLine="true"
android:focusable="true"
android:scrollHorizontally="true"
android:background="#000000ff"
android:textColor="#ff0000"
android:textSize="55dp"
android:textStyle="bold"
android:typeface="sans" />
</HorizontalScrollView>
Activity:
TextView scrollertextview = findViewById(R.id.translateanimatortextviewscroller);
textscroller = new AnimationAutoTextScroller(scrollertextview, screenwidth);
textscroller.setScrollingText(scrollertext);
textscroller.setDuration(60000);
textscroller.start();
Add this Animation file:
<translate
android:duration="7000"
android:fromYDelta="0%p"
android:interpolator="#android:anim/accelerate_interpolator"
android:repeatCount="10"
android:repeatMode="restart"
android:toYDelta="-100%p" />
/*Put your text view inside scroll*/
<ScrollView
android:layout_width="#dimen/dp_size_220"
android:layout_height="#dimen/dp_size_16"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/iv_myra_notification"
app:layout_constraintRight_toLeftOf="#+id/iv_one_way"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="#+id/marquee_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="left"
android:text="#{itemData.notification.message}"
android:textColor="#android:color/black"
android:textSize="12sp"
tools:text="bfnfkjnvlen jknjkgnojeng"/>
</ScrollView>
try this code it will help you out Shri n HERO
<?xml version="1.0" encoding="utf-8"?>
<translate>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:fromXDelta="1500"
android:interpolator="#android:anim/linear_interpolator"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toXDelta="-1250" />
</translate>
This is what worked for me.
Place your textview inside a scroll view and then perform TranslateAnimation on the scrollview's child, my case its the LinearLayout.
I am actually adding multiple views dynamically inside this linear layout.
<ScrollView android:id="#+id/textScrollView"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/textLayout"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
</ScrollView>
TranslateAnimation slide = new TranslateAnimation(0, 0, height, -textLayout.getHeight());
slide.setDuration(movementSpeed);
slide.setRepeatCount(-1);
slide.setRepeatMode(Animation.RESTART);
slide.setInterpolator(new LinearInterpolator());
textLayout.startAnimation(slide);
height --> The point start scrolling up (in my case device height (device bottom))
movementSpeed --> scrolling speed
Use this simple way with ellipsize and marquee options using #rajath answer
<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"/>
Its really frustrating,...
But the answer is simple,
Use Edittext instead of TextView, and wrap it in horizontalscrollview
At the same time, setfocusable: false
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:scrollbars="none">
<EditText
android:id="#+id/post_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:focusable="false"
android:outlineAmbientShadowColor="#color/colorPrimaryDark"
android:shadowColor="#000000"
android:shadowDx="1.5"
android:shadowDy="1.3"
android:shadowRadius="1.6"
android:singleLine="true"
android:textAlignment="center"
android:textColor="#color/colorPrimary"
android:textSize="20dp" />
</HorizontalScrollView>
Thanks to Hein, add the animation code
final EditText textView = view.findViewById(R.id.post_message);
textView.startAnimation((Animation) AnimationUtils.loadAnimation(context,R.anim.horizontal_animation));
String message="LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLong Text.";
textView.setText(message);
<translate>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:fromXDelta="1500"
android:interpolator="#android:anim/linear_interpolator"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toXDelta="-1250" />

Android: Last line of textview cut off

I have a horizontal LinearLayout containing a TextView followed by a Spinner next to it. This LinearLayout is dynamically inflated multiple times in a fixed vertical LinearLayout contained within a RelativeLayout.
The problem is that since I switched from Theme.light to Theme.holo.light, the last line of the TextView gets cut in half. This happens when the dynamic text is long and spans more than one row.
I have been able to fix this by adding bottom padding to the horizontal LinearLayout containing the TextView and Spinner.
This does not feel like a fix, but more of a hack. Can someone please give me some advice on how to properly fix this?
I have also read some other questions, but none seem to help.
Horizontal Linear layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/textView1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:text="TextView"/>
<Spinner
android:id="#+id/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Relative layout where above layout is dynamically inflated at Linear Layout with id ll2_7:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="#+id/scrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/relLayoutButtonNext"
android:layout_below="#id/textView1" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
<TextView
android:id="#+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="30dp"
android:text="2.7" />
<TextView
android:id="#+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_toRightOf="#id/textView10"
android:text="#string/question2_7" />
<LinearLayout
android:id="#+id/ll2_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView11"
android:layout_below="#+id/textView11"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
EDIT:
Here is the complete layout xml for above:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
style="#style/question_section_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="#string/question2_header" />
<RelativeLayout
android:id="#+id/relLayoutButtonNext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#color/bottomBar"
android:paddingBottom="3dp"
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:paddingTop="3dp" >
<Button
android:id="#+id/buttonNext"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:onClick="nextStep"
android:text="Next Section"
android:textSize="20sp" />
<Button
android:id="#+id/buttonPrevious"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:onClick="previousStep"
android:text="Previous Section"
android:textSize="20sp" />
</RelativeLayout>
<ScrollView
android:id="#+id/scrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/relLayoutButtonNext"
android:layout_below="#id/textView1" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
<TextView
android:id="#+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="30dp"
android:text="2.7" />
<TextView
android:id="#+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_toRightOf="#id/textView10"
android:text="#string/question2_7" />
<LinearLayout
android:id="#+id/ll2_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView11"
android:layout_below="#+id/textView11"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView10"
android:layout_below="#+id/ll2_7"
android:text="2.8" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_7"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_8" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView3"
android:layout_below="#+id/textView3"
android:layout_marginBottom="20dp"
android:orientation="vertical" >
</LinearLayout>
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView2"
android:layout_below="#+id/ll2_8"
android:text="2.9" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_8"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_9" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView5"
android:layout_toRightOf="#+id/textView10"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
<TextView
android:id="#+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView4"
android:layout_below="#+id/ll2_9"
android:text="2.10" />
<TextView
android:id="#+id/textView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_9"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_10" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView7"
android:layout_marginBottom="20dp"
android:layout_toRightOf="#+id/textView10"
android:orientation="vertical" >
</LinearLayout>
<TextView
android:id="#+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView6"
android:layout_below="#+id/ll2_10"
android:text="2.11" />
<TextView
android:id="#+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_10"
android:layout_toRightOf="#+id/textView10"
android:text="#string/quesiton2_11" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView9"
android:layout_below="#+id/textView9"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
<TextView
android:id="#+id/textView12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView8"
android:layout_below="#+id/ll2_11"
android:text="2.11.1" />
<TextView
android:id="#+id/textView13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/ll2_11"
android:layout_toRightOf="#+id/textView10"
android:text="#string/question2_11_1" android:layout_marginBottom="10dp"/>
<LinearLayout
android:id="#+id/ll2_11_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView13"
android:layout_toRightOf="#+id/textView10"
android:orientation="vertical" android:layout_marginBottom="20dp">
</LinearLayout>
</RelativeLayout>
</ScrollView>
</RelativeLayout>
I applied a LayoutGravity to the TextView item:
android:layout_gravity="fill"
I've encountered the same cut-off issue as shown at the screenshot. It is caused by the baseline alignment in the horizontal LinearLayout. TextView and Spinner have different baselines due to font size difference. To fix the issue it is needed to disable baseline alignment for the layout by setting:
android:baselineAligned="false"
or in the code:
layout.setBaselineAligned(false);
I had the same problem, and found that simply adding
android:includeFontPadding="false"
the final line of text no longer had its descenders clipped.
I added some dummy space after text by adding
textView.setText(firstString+"\n");
I tried all other solution.But this was the only solution worked for me
I found a different solution by extending TextView and adding a custom Class like this:
public class AdaptingTextView extends TextView {
public AdaptingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public AdaptingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AdaptingTextView(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// set fitting lines to prevent cut text
int fittingLines = h / this.getLineHeight();
if (fittingLines > 0) {
this.setLines(fittingLines);
}
}
}
Put the problematic textview inside a framelayout. I think the text view is not calculated correctly because of the sibling view, Spinner.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="150dp"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:text="TextView"/>
</FrameLayout>
<Spinner
android:id="#+id/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
When this occurs, you should ensure that the TextView is not growing larger than it's container -
If a TextView is set to wrap_content and it's container (or an ancestor container) doesn't leave room for the TextView to grow into it can be occluded.
If that's not the case, it's also possible the onMeasure() of the TextView sometimes doesn't correctly measure the tails of letters, non-latin characters or the effects from text being italic. You can correct for this by setting a global style for your TextView so it will be picked up without needed to change your entire code base:
Ensure that you're application/activities use a custom theme like so:
<style name="Custom" parent="#android:style/Theme.Light">
<item name="android:textViewStyle">#style/Custom.Widget.TextView</item>
</style>
<style name="Custom.Widget.TextView" parent="#android:style/Widget.TextView">
<item name="android:gravity">fill</item>
<item name="android:padding">1sp</item>
</style>
The answer by #Rynadt was really helpful in getting to the above stage. Setting the gravity of the Text inside the View ensures on some devices that occlusion never takes place (The text is correctly fitted inside the view), on others a helping hand with padding of an sp value, ensures that the tails et al are accounted for with a TextSize specific value.
My solution was close to the accepted one, but I had to change it to
android:layout_gravity="fill_vertical"
instead. Otherwise the other rows would have been stretch as well with added line breaks at random places. For example, the biggest row had 4 lines, so another row was changed from
this is a testphrase
to
thi
s is
a testph
rase
try with removing android:paddingBottom="20dp"
from
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
getViewTreeObserver().addOnGlobalLayoutListener does not work in a recycler view. If you're using a recycler, use View.addOnLayoutChangeListener:
I found that the ellipsizing I defined for textView in xml was not always reflected so I programmatically set it before reassigning the text property. This worked for me.
textView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
textView.removeOnLayoutChangeListener(this);
float lineHeight = textView.getLineHeight();
int maxLines = (int) (textView.getHeight() / lineHeight);
if (textView.getLineCount() != maxLines) {
textView.setLines(maxLines);
textView.setEllipsize(TextUtils.TruncateAt.END);
// Re-assign text to ensure ellipsize is performed correctly.
textView.setText(model.getText());
}
}
});
If you have this problem and your TextView is inside a RelativeLayout, try switching the RelativeLayout for a LinearLayout.
That fixed the problem for me
You can use a global layout listener for a TextView in any type of ViewGroup.
final TextView dSTextView = (TextView)findViewById(R.id.annoyingTextView);
dSTextView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
dSTextView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
float lineHeight = dSTextView.getLineHeight();
int maxLines = (int) (dSTextView.getHeight() / lineHeight);
if (dSTextView.getLineCount() != maxLines) {
dSTextView.setLines(maxLines);
}
}
});
You can read more about it here
I know it's so late, but this is work like charm for me.
add this code to your textview
android:ellipsize="marquee"
android:layout_weight="1"
I think there is very little you can do to get this working by altering the layouts. As I have found that some methods work only in some cases. I think it depends on the entire layout hierarchy and is not a one-size-fits-all solution. I have also noticed that it happens especially when you have a different font that you want to set to the TextView.
A sure shot method that I have experimented and tested is that you can set the font attributes in code after the view is inflated. I am assuming that you have a font in the assets/fonts folder that you want to you.
For eg in a Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_view, container, false);
TextView tv = (TextView)view.findViewById(R.id.text_view);
tv.setText("Insert text that needs to be displayed");
AssetManager assetManager = getContext().getAssets();
Typeface typeFace = Typeface.createFromAsset(assetManager, "Fonts/OpenSans-Light.ttf");
tv.setTypeface(typeFace , 0); // 0 is normal font
tv.setPadding(10, 0, 10, 0); // This is not mandatory
}
And in an Activity:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(Resource.Layout.main_activity);
TextView tv = (TextView)this.findViewById(R.id.text_view);
tv.setText("Insert text that needs to be displayed");
AssetManager assetManager = getContext().getAssets();
Typeface typeFace = Typeface.createFromAsset(assetManager, "Fonts/OpenSans-Light.ttf");
tv.setTypeface(typeFace , 0); // 0 is normal font
tv.setPadding(10, 0, 10, 0); // This is not mandatory
}
I have this same problem, and its very annoying.
It only happens with Arabic text.
If you make the label multi-line and adding a \n at the end of your string, it would fix it, but the problem is that there would be a big gap between this label and the object below it, due to the fact that this field now has a new empty line below it.
A custom control can be done to get around that. But overall, this is an annoying bug.
Best workaround for this is to add a dummy View of desired height (i.e. this will add padding itself) at the bottom of your view.
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" >
<View
android:layout_width="match_parent"
android:layout_height="30dp"/>
</TableRow>
Like in my case I added one more table row at the bottom of the view. Hope this could help someone.
Add padding to the bottom of the text view:
android:paddingBottom="24dp"
I had the same problem and found a handy solution. I get the number of lines of the TextView after rendering and set the height according to the number of lines. Here is the code.
TextView textView = (TextView) layout.findViewById(R.id.textView);
textView.setText(this.text);
textView.post(new Runnable() {
#Override
public void run() {
int linesCount = textView.getLineCount();
textView.setLines(linesCount);
}
});
For me, this solution worked like a charm.
The height and width of my outermost layout was set dynamically, so the TextView contained within got it's text cut even if I set android:maxLines in my xml (for different devices it was behaving differently).
After trying out different methods, finally I got a solution that fixed my issue.
Textview:
public class CustomTextView extends androidx.appcompat.widget.AppCompatTextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// set fitting lines to prevent cut text
int fittingLines = h / this.getLineHeight();
if (fittingLines > 0) {
this.setLines(fittingLines);
this.setEllipsize(TextUtils.TruncateAt.END);
}
}
}
xml:
<com.myproject.android.customviews.CustomTextView
android:id="#+id/tv_partner_description"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top"
android:textColor="#color/white"
android:textSize="#dimen/text_small_medium" />
create theme as for particular language like style-ar which cut-off textview:
<style name="EnnodaCustomTextView" parent="Widget.AppCompat.TextView">
<item name="android:paddingTop">1dp</item>
<item name="android:paddingBottom">1dp</item>
</style>
Apply it in you AppTheme to reflect in overall app for padding bottom, as :
<item name="android:textViewStyle">#style/EnnodaCustomTextView</item>
Note : create same style name in default styles.xml with no item tags for padding..(where no need of extra padding )
I finally fixed it!
I try to add String to the TextView in Service and then call scrollTo(), the last line be cut off!
The scrollTo() should be call in "Runnable", like:
private ScrollView mScrollView;
public void scrollToBottom()
{
mScrollView = (ScrollView) findViewById(R.id.debug_textview_scrollview);
mScrollView.post(new Runnable()
{
public void run()
{
mScrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
I think it because in the monent of call scrollTo() in service, the update of TextView is not ready.

Categories

Resources