Is there a way to make ellipsize="marquee" always scroll?

AndroidTextviewMarquee

Android Problem Overview


I want to use the marquee effect on a TextView, but the text is only being scrolled when the TextView gets focus. That's a problem, because in my case, it can't.

I am using:

  android:ellipsize="marquee"
  android:marqueeRepeatLimit="marquee_forever"

Is there a way to have the TextView always scroll its text? I've seen this being done in the Android Market app, where the app name will scroll in the title bar, even if it doesn't receive focus, but I couldn't find this being mentioned in the API docs.

Android Solutions


Solution 1 - Android

I finally came up against this problem today and so fired up hierarchyviewer on the Android Market application.

Looking at the title on an app's detail screen, they use a plain old TextView. Examining its properties showed that it wasn't focused, couldn't be focused and was generally very ordinary — except for the fact that it was marked as selected.

One line of code later and I had it working :)

textView.setSelected(true);

This makes sense, given what the Javadoc says:

> A view can be selected or not. Note that selection is not the same as focus. Views are typically selected in the context of an AdapterView like ListView or GridView.

i.e. When you scroll over an item in a list view (like in the Market app), only then does the now-selected text start scrolling. And since this particular TextView isn't focusable or clickable, it will never lose its selection state.

Unfortunately, as far as I know there is no way to pre-set the selected state from the layout XML.
But the one-liner above works fine for me.

Solution 2 - Android

Just put these parameters in your TextView. It works :)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 

Solution 3 - Android

I have been facing the problem and the shortest solution I have come up with is to create a new class derived from TextView. The class should override three methods onFocusChanged, onWindowFocusChanged and isFocused to make the TextView all focused.

@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;
}

Solution 4 - Android

TranslateAnimation works by "pulling" the View in one direction by a specified amount. You can set where to start this "pulling" and where to end.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta set the offset of the starting position of the movement in the X axis.

fromXDelta = 0 //no offset. 
fromXDelta = 300 //the movement starts at 300px to the right.
fromXDelta = -300 //the movement starts at 300px to the left

toXDelta defines the offset ending position of the movement in the X axis.

toXDelta = 0 //no offset. 
toXDelta = 300 //the movement ends at 300px to the right.
toXDelta = -300 //the movement ends at 300px to the left.

If the width of your text is greater that the module of the difference between fromXDelta and toXDelta, the text won't be able to totaly and compeltely move within the screen.


Example

Let's assume our screen size is 320x240 pxs. We have a TextView with a text that has 700px width and we wish to create an animation that "pulls" the text so that we can see the end of the phrase.

                                       (screen)
                             +---------------------------+
                             |<----------320px---------->|
                             |                           |
                             |+---------------------------<<<< X px >>>>
               movement<-----|| some TextView with text that goes out...
                             |+---------------------------
                             |  unconstrained size 700px |
                             |                           |
                             |                           |
                             +---------------------------+
                             

                             +---------------------------+
                             |                           |
                             |                           |
               <<<< X px >>>>---------------------------+|
movement<----- some TextView with text that goes out... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

First we set fromXDelta = 0 so that the movement doesn't have a starting offset. Now we need to figure the toXDelta value. To achieve the desired effect we need to "pull" the text the exact same px that it spans out of the screen. (in the scheme is represented by <<<< X px >>>>) Since our text has 700 width, and the visible area is 320px (screen width) we set:

tXDelta = 700 - 320 = 380

And how do we figure the Screen Width and the text Width?


Code

Taking the Zarah Snippet as a starting point:

    /**
     * @param view The Textview or any other view we wish to apply the movement
     * @param margin A margin to take into the calculation (since the view
     *               might have any siblings in the same "row")
     *
     **/
public static Animation scrollingText(View view, float margin){
	
	Context context = view.getContext(); //gets the context of the view
	
            // measures the unconstrained size of the view
            // before it is drawn in the layout
	view.measure(View.MeasureSpec.UNSPECIFIED, 
                         View.MeasureSpec.UNSPECIFIED); 
	
            // takes the unconstrained wisth of the view
	float width = view.getMeasuredWidth();
	
            // gets the screen width
	float screenWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();
	

            // perfrms the calculation
	float toXDelta = width - (screenWidth - margin);
	
            // sets toXDelta to 0 if the text width is smaller that the screen size
	if (toXDelta < 0) {toXDelta = 0; } else { toXDelta = 0 - toXDelta;}
	
            // Animation parameters
	Animation mAnimation = new TranslateAnimation(0, toXDelta, 0, 0);
	mAnimation.setDuration(15000); 
	mAnimation.setRepeatMode(Animation.RESTART);
	mAnimation.setRepeatCount(Animation.INFINITE);
	
	return mAnimation;
}

There might be easier ways to perform this, but this works for every view you can think of and is reusable. It is specially usefull if you want to animate a TextView in a ListView without breaking the enabled/onFocus abilities of the textView. It also scrolls continuously even if the View is not focused.

Solution 5 - Android

I don't know if you still need the answer, but I found an easy way to do this.

Set up your animation like so:

Animation mAnimation = new TranslateAnimation(START_POS_X, END_POS_X, 
				START_POS_Y, END_POS_Y);
mAnimation.setDuration(TICKER_DURATION); 
mAnimation.setRepeatMode(Animation.RESTART);
mAnimation.setRepeatCount(Animation.INFINITE);

START_POS_X, END_POS_X, START_POS_Y and END_POS_Y are float values, while TICKER_DURATION is an int I declared with my other constants.

Then you can now apply this animation to your TextView:

TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);

And that's it. :)

My animation starts on the right side off-screen (300f) and ends on the left side off-screen(-300f), with a duration of 15s (15000).

Solution 6 - Android

I wrote the following code for a ListView with marquee text items. It is based on the setSelected solution described above. Basically, I am extending the ArrayAdapter class and override the getView method to select the TextView before returning it:

	// Create an ArrayAdapter which selects its TextViews before returning 		
	// them. This would enable marqueeing while still making the list item
	// clickable.
	class SelectingAdapter extends ArrayAdapter<LibraryItem>
	{
		public
		SelectingAdapter(
			Context context, 
			int resource, 
			int textViewResourceId, 
			LibraryItem[] objects
		)
		{
			super(context, resource, textViewResourceId, objects);
		}
		
		@Override
		public
		View getView(int position, View convertView, ViewGroup parent)
		{
			View view = super.getView(position, convertView, parent);
			TextView textview = (TextView) view.findViewById(
				R.id.textview_playlist_item_title
			);
			textview.setSelected(true);
			textview.setEnabled(true);
			textview.setFocusable(false);
			textview.setTextColor(0xffffffff);
			return view;
			
		}
	}

Solution 7 - Android

This is the answer that pops up at the top of my google search so I thought I could post a useful answer here since I struggle with remembering this fairly often. Anyway, this works for me and requires XML attributes and A an onFocusChangeListener.

//XML
        <TextView
            android:id="@+id/blank_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:layout_gravity="center_horizontal|center_vertical"
            android:background="#a4868585"
            android:textColor="#fff"
            android:textSize="15sp"
            android:singleLine="true"
            android:lines="1"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit ="marquee_forever"
            android:scrollHorizontally="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            tools:ignore="Deprecated" />

//JAVA
    titleText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                titleText.setSelected(true);
            }
        }
    });

Solution 8 - Android

// xml

 <TextView
            android:id="@+id/tvMarque"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:layout_gravity="center_horizontal"
            android:fadingEdge="horizontal"
            android:marqueeRepeatLimit="marquee_forever"
            android:scrollHorizontally="true"
            android:padding="5dp"
            android:textSize="16sp"
            android:text=""
            android:textColor="@color/colorSyncText"
            android:visibility="visible" />

// In Java

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatthiasView Question on Stackoverflow
Solution 1 - AndroidChristopher OrrView Answer on Stackoverflow
Solution 2 - AndroidVinayakView Answer on Stackoverflow
Solution 3 - AndroidhnvietView Answer on Stackoverflow
Solution 4 - AndroidTivieView Answer on Stackoverflow
Solution 5 - AndroidZarahView Answer on Stackoverflow
Solution 6 - AndroidsmichakView Answer on Stackoverflow
Solution 7 - AndroidThunderstickView Answer on Stackoverflow
Solution 8 - AndroidSoni KumarView Answer on Stackoverflow