开发者

Android and a TextView's horizontal marquee scroll rate

开发者 https://www.devze.com 2023-02-11 13:37 出处:网络
I have a text view with following XML attributes: <TextView android:layout_width=\"match_parent\" android:layout_height=\"wrap_content\"

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开发者_如何学JAVA the default. How do I do with this (in XML)?

Thanking you in advance.


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.


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


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


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");
}
0

精彩评论

暂无评论...
验证码 换一张
取 消