7

I have custom gallery. Gallery represents items that are frame layout. There are one imageView and textView above it.

If text in textView is too long, i need it to be scrolled automatically. It's one line of text, and it's needed to be scrolled horizontally.

I've found this snippet of code:

TextView
    android:text="Single-line text view that scrolls automatically"       
    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"/>   

It works in my test app with only one text view in it. But it doesn't work in my gallery. Noting happens, text just stay still.

Any help?

Veljko
  • 1,823
  • 6
  • 27
  • 55
  • I came across this behavior once and finally fixed the problem by calling .setFocus() on the textView. It wasn't in a gallery so I'm not sure if you are having the same problem but its an easy fix so it's worth a shot! – ByteMe Mar 16 '12 at 00:54

9 Answers9

17

Try this custom TextView class:

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

and set the following XML attributes:

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

This works beautifully in my dictionary apps where multiple entries may need to auto-scroll simultaneously to display complete content.

Kai
  • 14,428
  • 6
  • 46
  • 78
6

The marquee effect on a TextView is only designed to work when the view is focused or selected. The XML code you have tries to make the TextView focused all the time. Unfortunately, since only one view can be focused at any time, and since you have multiple views in the gallery, this approach will not work for you.

The easiest way to accomplish this otherwise is to make the TextViews always be selected. Multiple TextViews can hold the selected state at one time. Selection is meant to be used for an active element of an AdapterView, but still works outside of one. Firstly, remove the attributes modifying the focus from the XML and then just call TextView.setSelected(true) sometime after the view is initialised, e.g. in Activity.onCreate(Bundle) (there is no XML attribute for this). If you are supplying the views from an adapter, then you can call TextView.setSelected(true) during the getView() method after you inflate the view.

Here is an example project showing marquee working for multiple TextViews, and the behaviour inside a Gallery.

antonyt
  • 21,626
  • 9
  • 66
  • 68
  • Can you write me down what should I put into xml file? TextView android:text="Single-line text view that scrolls automatically" android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit ="marquee_forever" android:scrollHorizontally="true" android:layout_width="wrap_content" android:layout_height="wrap_content"/> I've typed this, and in a getView method put setSelected(true) but still nothing happens. – Veljko Mar 11 '12 at 08:26
  • Using those params you have, I can get TextView marquee to work in a Gallery aside from the first element, which does not scroll until you go to another element, and then they all scroll automatically. Is this what you see? I do not know how to fix it for a Gallery, but this approach works fine in getting multiple TextViews to marquee if they were just in your activity layout. – antonyt Mar 11 '12 at 10:20
  • I've done what you said, but none of elements are scrolling...they just stay still. :/ Give me some sample code...if you can... – Veljko Mar 11 '12 at 13:10
1

Try using ViewPager instead of gallery. This is available in android support packages. http://android-developers.blogspot.in/2011/08/horizontal-view-swiping-with-viewpager.html

arjoan
  • 1,819
  • 1
  • 20
  • 38
1

I've tried everything, and finally came up with this. This works for me...hope that this will help you someday. Cheers.

 package com.gui.custom_views;

 import android.content.Context;
 import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.text.TextUtils; 
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Animation;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.TranslateAnimation;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;

 import com.media_player.AndroidMediaPlayerActivity;

 /**
 * Custom Automatic Scrollable Text View
 * 
 * @author Veljko Ilkic
 * 
 */
 public class AutomaticScrollTextView extends LinearLayout {

// Context of application
Context context;
// TextView
private TextView mTextField1;

// Horizontal scroll
private ScrollView mScrollView1;

// Animation on start
private Animation mMoveTextOnStart = null;
// Out animation
private Animation mMoveText1TextOut = null;

// Duration of animation on start
private int durationStart;
// Duration of animation
private int duration;

// Pain for drawing text
private Paint mPaint;

// Text current width
private float mText1TextWidth;

/**
 * Control the speed. The lower this value, the faster it will scroll.
 */
public static final int MS_PER_PX = 80;

/**
 * Control the pause between the animations. Also, after starting this
 * activity.
 */
public static final int PAUSE_BETWEEN_ANIMATIONS = 0;
private boolean mCancelled = false;

// Layout width
private int mWidth;
// Animation thread
private Runnable mAnimation1StartRunnable;

public AutomaticScrollTextView(Context context) {
    super(context);
    init(context);
    this.context = context;
}

public AutomaticScrollTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
    this.context = context;
}

private void init(Context context) {
    initView(context);

    // init helper
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStrokeWidth(1);
    mPaint.setStrokeCap(Paint.Cap.ROUND);

}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);

    mWidth = getMeasuredWidth();

    // Calculate
    prepare();

    // Setup
    setupText1Marquee();

}

@Override
public void setOnClickListener(OnClickListener l) {
    super.setOnClickListener(l);

    mTextField1.setOnClickListener(l);
}

// Method to finally start the marquee.
public void startMarquee() {
    prepare();
    prepareTextFields();

    startTextField1Animation();

    mCancelled = false;
}

private void startTextField1Animation() {
    mAnimation1StartRunnable = new Runnable() {
        public void run() {
            mTextField1.setVisibility(View.VISIBLE);
            mTextField1.startAnimation(mMoveTextOnStart);
        }
    };
    postDelayed(mAnimation1StartRunnable, PAUSE_BETWEEN_ANIMATIONS);
}

public void reset() {

    mCancelled = true;

    if (mAnimation1StartRunnable != null) {
        removeCallbacks(mAnimation1StartRunnable);
    }

    mTextField1.clearAnimation();

    prepareTextFields();

    mMoveTextOnStart.reset();
    mMoveText1TextOut.reset();

    mScrollView1.removeView(mTextField1);
    mScrollView1.addView(mTextField1);

    mTextField1.setEllipsize(TextUtils.TruncateAt.END);

    invalidate();
}

public void prepareTextFields() {
    mTextField1.setEllipsize(TextUtils.TruncateAt.END);
    mTextField1.setVisibility(View.INVISIBLE);
    expandTextView(mTextField1);
}

private void setupText1Marquee() {

    // Calculate duration of animations
    durationStart = (int) ((mWidth + mText1TextWidth) * MS_PER_PX);
    duration = (int) (2 * mWidth * MS_PER_PX);

    // On start animation
    mMoveTextOnStart = new TranslateAnimation(0, -mWidth - mText1TextWidth,
            0, 0);

    mMoveTextOnStart.setDuration(durationStart);
    mMoveTextOnStart.setInterpolator(new LinearInterpolator());
    mMoveTextOnStart.setFillAfter(true);

    // Main scrolling animation
    mMoveText1TextOut = new TranslateAnimation(mWidth, -mWidth
            - mText1TextWidth, 0, 0);

    mMoveText1TextOut.setDuration(duration);
    mMoveText1TextOut.setInterpolator(new LinearInterpolator());
    mMoveText1TextOut.setFillAfter(true);
    mMoveText1TextOut.setRepeatCount(Animation.INFINITE);

    // Animation listeners
    mMoveTextOnStart
            .setAnimationListener(new Animation.AnimationListener() {
                public void onAnimationStart(Animation animation) {
                    invalidate();
                    mTextField1.invalidate();

                }

                public void onAnimationEnd(Animation animation) {

                    if (mCancelled) {
                        return;
                    }

                    mTextField1.startAnimation(mMoveText1TextOut);

                }

                public void onAnimationRepeat(Animation animation) {
                    invalidate();
                    mTextField1.invalidate();
                }
            });

    mMoveText1TextOut
            .setAnimationListener(new Animation.AnimationListener() {
                public void onAnimationStart(Animation animation) {
                    invalidate();
                    mTextField1.invalidate();

                }

                public void onAnimationEnd(Animation animation) {

                    if (mCancelled) {
                        return;
                    }

                }

                public void onAnimationRepeat(Animation animation) {
                    invalidate();
                    mTextField1.invalidate();
                }
            });

}

private void prepare() {

    // Measure
    mPaint.setTextSize(mTextField1.getTextSize());
    mPaint.setTypeface(mTextField1.getTypeface());
    mText1TextWidth = mPaint.measureText(mTextField1.getText().toString());

    setupText1Marquee();

}

private void initView(Context context) {
    setOrientation(LinearLayout.VERTICAL);
    setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.FILL_PARENT, Gravity.LEFT));
    setPadding(0, 0, 0, 0);

    // Scroll View 1
    LayoutParams sv1lp = new LayoutParams(LayoutParams.FILL_PARENT,
            LayoutParams.WRAP_CONTENT);
    sv1lp.gravity = Gravity.CENTER_HORIZONTAL;
    mScrollView1 = new ScrollView(context);

    // Scroll View 1 - Text Field
    mTextField1 = new TextView(context);
    mTextField1.setSingleLine(true);
    mTextField1.setEllipsize(TextUtils.TruncateAt.END);
    mTextField1.setTypeface(null, Typeface.BOLD);

    mScrollView1.addView(mTextField1, new ScrollView.LayoutParams(
            mTextField1.getWidth(), LayoutParams.WRAP_CONTENT));

    addView(mScrollView1, sv1lp);
}

public void setText1(String text) {

    String temp = "";
    if (text.length() < 10) {
        temp = "         " + text + "         ";
    } else {
        temp = text;
    }
    mTextField1.setText(temp);

}

public void setTextSize1(int textSize) {
    mTextField1.setTextSize(textSize);
}

public void setTextColor1(int textColor) {

    mTextField1.setTextColor(textColor);
}

private void expandTextView(TextView textView) {
    ViewGroup.LayoutParams lp = textView.getLayoutParams();
    lp.width = AndroidMediaPlayerActivity.getScreenWidth();
    textView.setLayoutParams(lp);
}
}
Veljko
  • 1,823
  • 6
  • 27
  • 55
  • Veljko, this class com.media_player.AndroidMediaPlayerActivity is missing, can you please complete this mising class? – exequielc Dec 12 '12 at 15:21
  • AndroidMediaPlayerActivity contains public static field that contains screen width of the device. – Veljko Jun 21 '13 at 09:57
0

This code is working properly for me.

scrollview=(ScrollView)findViewById(R.id.scrollview1); tb2.setTextSize(30);

    tb2.setMovementMethod(new ScrollingMovementMethod());
    scrollview.post(new Runnable() { 
    public void run() { 
        scrollview.fullScroll(View.FOCUS_DOWN);  
        }
    });
Amitsharma
  • 1,519
  • 1
  • 17
  • 29
0
public class ScrollingTextView extends TextView {

    public ScrollingTextView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
    }

    public ScrollingTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrollingTextView(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;
    }
}

 <com.test.autoscroll.ScrollingTextView
                android:id="@+id/actionbar_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingLeft="10dip"
                android:paddingRight="10dip"
                android:textSize="16dip"
                android:textStyle="bold"
                android:lines="1"
                android:scrollHorizontally="true"
                android:ellipsize="marquee"
                 android:text="autoscrollable textview without focus to textview...working...."
                android:marqueeRepeatLimit="marquee_forever"
                />
DeepakPanwar
  • 1,350
  • 14
  • 19
0

Add this code to your own

findViewById(R.id.yourtextviewid).setSelected(true);

maybe your problem is fixed.

NearHuscarl
  • 12,341
  • 5
  • 39
  • 69
Kurdev
  • 29
  • 7
0

I came across this problem once and finally fixed the problem by calling .setFocus() on the textView.

ByteMe
  • 1,356
  • 11
  • 15
0

Hi You have Tag in the xml file itself. And also use the Scrollview Property of FOCUS_DOWN in the java file ... Hope It helps to u ...

itsrajesh4uguys
  • 4,420
  • 3
  • 18
  • 31