Android: 如何从带有跑马灯效果的TextView中去除末尾空格

5
我创建了一个带有跑马灯效果的TextView,但我想要去掉在重新显示文本前末尾和开头之间的空格。

这是屏幕截图:

http://i.stack.imgur.com/dfdT8.png

这是我的布局:

<TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:marqueeRepeatLimit="marquee_forever"
        android:scrollHorizontally="true"
        android:singleLine="true"
        android:text="dkfjdkf jdfjfsfjkfa asdfjakjfdkasf sfdjaskfjdksf sfdjsfjk gfhgfhfai ggfghgf" />

如果您觉得可以接受,可以尝试下一个解决方法。 您应该创建包含2或3个目标短语的文本。 例如,如果您的短语是“Hello world”,则应创建“Hello world Hello world Hello world”并将其设置为TextView。 - ant
你能展示一下完整的布局文件吗?你可能漏掉了一些约束条件。 - tk1505
这是我的布局<TextView android:id="@+id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="dkfjdkf jdfjfsfjkfa asdfjakjfdkasf sfdjaskfjdksf sfdjsfjk gfhgfhfai ggfghgf" android:ellipsize="marquee" android:focusable="true" android:focusableInTouchMode="true" android:marqueeRepeatLimit="marquee_forever" android:scrollHorizontally="true" android:singleLine="true" android:layout_alignParentTop="true" android:layout_alignParentStart="true" /> - 123456
我认为@123456想要的是类似于setSpacing(0)的东西,以消除文本末尾和开头之间的间隙,解决方案找到了吗? 我也想要。 - Beeing Jk
3个回答

0

使用:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

0
如果您所指的空白是指TextView前后的黑色条纹,您可以通过将布局宽度调整为android:layout_width="match_parent"来解决。
<TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:marqueeRepeatLimit="marquee_forever"
        android:scrollHorizontally="true"
        android:singleLine="true"
        android:text="dkfjdkf jdfjfsfjkfa asdfjakjfdkasf sfdjaskfjdksf sfdjsfjk gfhgfhfai ggfghgf" />

此外,请确保该 TextView 的父布局没有应用任何边距。

match_parent 不会有任何变化 - 123456

0
这个方案适用于 API 28 及之前,当他们引入 非 SDK 接口限制 后就不再适用了。

我遇到了同样的问题,但在网上找不到解决方案。通过查看TextView的源代码并参考其他提供控制滚动速度选项的答案,我设法自己解决了这个问题。

查看源代码,它将间隙或空白设置为您的TextView大小的1/3。因此,如果您的TextView宽度为600像素,则会在消息的开始和结束之间创建200像素的间隙。此解决方案旨在使该值可配置。

棘手的部分是,您需要覆盖的逻辑都在超类的私有类、字段和方法中。这使得解决方案变得不那么琐碎。

将此类添加到您的项目中... CustomTextView.java

public class CustomTextView extends AppCompatTextView {

    private static final float NEW_GAP = 0F;

    Object marqueeObject;
    Field mStatusField;
    Field mGhostStartField;
    Field mMaxScrollField;
    Field mGhostOffsetField;
    Field mFadeStopField;
    Field mMaxFadeScrollField;

    public CustomTextView(Context context) {
        super(context);
        setSelected(true);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setSelected(true);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setSelected(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        try {
            initMarqueeObject();

            if (didMarqueeRestart()) {
                // We need to update the values each time it restarts
                updateMarqueeFieldValues();
            }
        }
        catch(Exception exception) {
            exception.printStackTrace();
        }

        super.onDraw(canvas);
    }

    private void initMarqueeObject() throws Exception {
        if (marqueeObject == null) {
            Field marqueeField = getClass().getSuperclass().getSuperclass().getDeclaredField("mMarquee"); // use if extending from AppCompatTextView
            // Field marqueeField = getClass().getSuperclass().getDeclaredField("mMarquee"); // use if extending from TextView
            marqueeField.setAccessible(true);
            marqueeObject = marqueeField.get(this);
            initMarqueeFields();
        }
    }

    private void initMarqueeFields() throws Exception {
        mStatusField = marqueeObject.getClass().getDeclaredField("mStatus");
        mStatusField.setAccessible(true);
        mGhostStartField = marqueeObject.getClass().getDeclaredField("mGhostStart");
        mGhostStartField.setAccessible(true);
        mMaxScrollField = marqueeObject.getClass().getDeclaredField("mMaxScroll");
        mMaxScrollField.setAccessible(true);
        mGhostOffsetField = marqueeObject.getClass().getDeclaredField("mGhostOffset");
        mGhostOffsetField.setAccessible(true);
        mFadeStopField = marqueeObject.getClass().getDeclaredField("mFadeStop");
        mFadeStopField.setAccessible(true);
        mMaxFadeScrollField = marqueeObject.getClass().getDeclaredField("mMaxFadeScroll");
        mMaxFadeScrollField.setAccessible(true);
    }

    private boolean didMarqueeRestart() throws Exception {
        byte currentState = mStatusField.getByte(marqueeObject);
        return currentState == 0x1; // 0x1 is the byte object for the MARQUEE_STARTING state
    }

    private void updateMarqueeFieldValues() throws Exception {
        float textWidth = getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight();
        float originalGap = textWidth / 3.0F;
        // We have to calculate the lineWidth based on the original value
        float originalValueStartValue = mGhostStartField.getFloat(marqueeObject);
        float lineWidth = originalValueStartValue + textWidth - originalGap;
        float mGhostStart = lineWidth - textWidth + NEW_GAP;
        mGhostStartField.setFloat(marqueeObject, mGhostStart);
        mMaxScrollField.setFloat(marqueeObject, mGhostStart + textWidth);
        mGhostOffsetField.setFloat(marqueeObject, lineWidth + NEW_GAP);
        mFadeStopField.setFloat(marqueeObject, lineWidth);
        mMaxFadeScrollField.setFloat(marqueeObject, mGhostStart + lineWidth + lineWidth);
    }
}

现在您可以使用NEW_GAP变量轻松调整额外的空白间距。在此示例中,它设置为0像素。将该常量设置为您希望使用的任何像素值。

注意:此解决方案是从AppCompatTextView扩展的。如果您正在从TextView扩展,则应取消注释initMarqueeObject()方法中的相关代码。

然后,只需在XML中将旧TextView替换为这个新类即可...

<com.yourpackagename.CustomTextView
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:singleLine="true"
    android:scrollHorizontally="true"
    android:ellipsize="marquee"
    android:marqueeRepeatLimit="marquee_forever"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

在您的代码中不需要调用setSelected(true),因为这在新类内部已经完成。

这种方法可能不会永远有效,因为如果他们重命名某些变量或更改TextView的逻辑,它将会失效。但是在我测试过的所有版本中,它都运行良好。

希望这可以帮到您!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接