最近工作中遇到了一个跑马灯怎么样做都不能愉快跑起来的问题,是这样的,我要动态添加一个通知栏,那通知栏里的内容就是跑马灯,但是要求是超过20个字才会跑马灯,其余的正常展示,那这个要怎么搞呢?有童鞋可能说了,设置maxLength为20不就可以了,然后让宽度自适应,不过很遗憾,这样并不可行,原因很简单,跑马灯效果的实现是需要确切知道宽度才能跑起来的。但是仅仅有宽度就够了,再次遗憾告诉你,这还远远不够,除了必要的属性之外,动态添加TextView需要考虑到容器的容纳问题,就是textview其实还没有加进去,也就是父布局其实仍然对这个textview一无所知,因此为了能够跑起来,我们需要异步调用textview.setSelected(true),方法就是通过view.post(new Runnable()),事实上无需调用delay方法。

     那么textview的setSelected方法是做什么用的呢,首先我们来看下下面截取的部源码:

...省略...
 @Override
    public void setSelected(boolean selected) {
        boolean wasSelected = isSelected();

        super.setSelected(selected);

        if (selected != wasSelected && mEllipsize == TextUtils.TruncateAt.MARQUEE) {
            if (selected) {
                startMarquee();
            } else {
                stopMarquee();
            }
        }
    }
...省略...

很明显,这个方法是告诉textview我被选中了,我可以开始跑马灯了。由于startMarquee的条件也很复杂,只有最终满足条件的才能愉快的跑起来。

下面看下我的解决方案:

noticeTextView = (MarqueeTextView) View.inflate(getContext(), R.layout.marque_textview, null);
            params.height = ResUtils.getDimenToInt(R.dimen.y52);
            //动态设置宽度,最多显示20个字符,多余20个字符显示跑马灯
            final String content = info.getContent();
            if (content.length() > MARQUEE_MAX_LENGTH) {
                noticeTextView.setHorizontalFadingEdgeEnabled(true);
                int vWidth = ViewUtils.computeTextWidthDynamic(content.substring(0, MARQUEE_MAX_LENGTH), ResUtils.getDimensionPixelSize(R.dimen.x26));
                params.width = vWidth + ResUtils.getDimenToInt(R.dimen.x56);
                post(() -> noticeTextView.setSelected(true));
            } else {
                //非跑马灯去除左右阴影
                noticeTextView.setHorizontalFadingEdgeEnabled(false);
                noticeTextView.setEllipsize(null);
            }
            noticeTextView.setText(content);

   computeTextWidthDynamic方法只是动态计算超过20个字之后的宽度,以此来设置宽度实现跑马灯。

 还有一点我需要告诉大家,如果一开始不能设置宽度,通过异步获取自适应的宽度之后再去重新设置宽度以及调用setSelected(true)也是无效的,这些都是开发中测试过的。当然如果大家还有什么意见或者感觉我现在的解释有问题,欢迎指出。