5

I have a text view with following XML attributes:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="14dip"
    android:maxLines="1"
    android:scrollHorizontally="true"
    android:ellipsize="marquee"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:marqueeRepeatLimit="1"
    android:textColor="@android:color/black"
    android:id="@+id/ticker"
    />

I'd like to be able to set the horizontal scroll rate, making it slightly faster than the default. How do I do with this (in XML)?

Thanking you in advance.

Ken
  • 30,811
  • 34
  • 116
  • 155

4 Answers4

8

I don't think there's an attribute that you can set in XML for that purpose.

It might be a bit overkill for you, but check out this customized extended marquee for Android, all settings can be customized in the coding part, you need to play with setDuration of the animation to achieve the speed you want.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
SteD
  • 13,909
  • 12
  • 65
  • 76
5

Here's how I did it, it's dirty but it gets the job done, until they wake-up and make it configurable!

Could you believe there's a "// TODO Add an option to configure this" in the Marquee private static inner class!

    protected void setMarqueeSpeed(TextView tv, float speed, boolean speedIsMultiplier) {

    try {
        Field f = tv.getClass().getDeclaredField("mMarquee");
        f.setAccessible(true);
        Object marquee = f.get(tv);
        if (marquee != null) {
            Field mf = marquee.getClass().getDeclaredField("mScrollUnit");
            mf.setAccessible(true);
            float newSpeed = speed;
            if (speedIsMultiplier) {
                newSpeed = mf.getFloat(marquee) * speed;
            }
            mf.setFloat(marquee, newSpeed);
            Log.i(this.getClass().getSimpleName(), String.format("%s marquee speed set to %f", tv, newSpeed));
        }
    } catch (Exception e) {
        // ignore, not implemented in current API level
    }
}
Mike
  • 1,390
  • 1
  • 12
  • 17
  • I don't believe that - hilarious! Thanks for the post too. – Ken Feb 27 '11 at 10:49
  • 5
    Strange... f.get(tv) returns null for me. I'm setting ellipsize to "marquee" in the xml, so I would think that the "mMarquee" variable would be set. The textview still scrolls, just not at the speed I'm trying to set with the above piece of nifty code. Any ideas? – SilithCrowe Apr 01 '11 at 17:06
  • 1
    f.get(tv) returns null for me also. java.lang.reflect.field.get() seems to say it should not be null; mMarquee is private and not static. Hmm.. this on Android 2.2.2 – DJC Jun 12 '11 at 05:43
  • 1
    Returns `null` here too, on an HTC Hero (2.1-update1) and LG Optimus 2X Speed (a.k.a. LG-P990 with 2.2.2). – Paul Lammertsma Jul 01 '11 at 20:37
  • 1
    Why it doesn't have effect for me at all? – Laurynas G Mar 19 '13 at 03:28
2

This is my first answer on SO, so I don't have reputation so I can't comment on Mike's answer, but I modified it a little bit to make it work with Android L.

Besides that, if f.get(tv) returns null, try calling mTextView.setSelected(true) before calling setMarqueeSpeed(). This worked for me.

protected void setMarqueeSpeed(TextView tv, float speed, boolean speedIsMultiplier) {

    try {
        Field f = tv.getClass().getDeclaredField("mMarquee");
        f.setAccessible(true);

        Object marquee = f.get(tv);
        if (marquee != null) {

            String scrollSpeedFieldName = "mScrollUnit";
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.L)
                scrollSpeedFieldName = "mPixelsPerSecond";

            Field mf = marquee.getClass().getDeclaredField(scrollSpeedFieldName);
            mf.setAccessible(true);

            float newSpeed = speed;
            if (speedIsMultiplier)
                newSpeed = mf.getFloat(marquee) * speed;

            mf.setFloat(marquee, newSpeed);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Thomas Nielsen
  • 162
  • 1
  • 4
0

Just an addition to Mike's answer. Because it returns NoSuchFieldException when working with AppCompatActivity:

Field f;     
if (tv instanceof AppCompatTextView) {
    f = tv.getClass().getSuperclass().getDeclaredField("mMarquee");
} else {
    f = tv.getClass().getDeclaredField("mMarquee");
}
Ahmed
  • 125
  • 1
  • 4