Android TextView跑马灯无法启动问题

原创
2022/12/13 15:44
阅读数 64

一、跑马灯需要满足的条件

    private void startMarquee() {
        // Do not ellipsize EditText
        if (getKeyListener() != null) return;

        if (compressText(getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight())) {
//宽度大于0,或者硬件加速
            return;
        }


        if ((mMarquee == null || mMarquee.isStopped()) && (isFocused() || isSelected())
                && getLineCount() == 1 && canMarquee()) {

           //获焦或者selected状态,由于focus相对于selected复杂,建议使用selected
 //TextLayout行数必须为1

            if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
                mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_FADE;
                final Layout tmp = mLayout;
                mLayout = mSavedMarqueeModeLayout;
                mSavedMarqueeModeLayout = tmp;
                setHorizontalFadingEdgeEnabled(true);
                requestLayout();
                invalidate();
            }

            if (mMarquee == null) mMarquee = new Marquee(this);
            mMarquee.start(mMarqueeRepeatLimit);
        }
    }

二、代码

鉴于有博客使用focus驱动跑马灯,但这种调用可能产生焦点判断问题,非常不推荐。因此使用这里避免外部调用selected可以以很小代价实现跑马灯,如果非要使用setSelected,系统中有个setActivated和setEnable可以用来代替setSelected。

public class MarqueeTextView extends AppCompatTextView {

    private static final String TAG = "MarqueeTextView";
    private boolean isMarqueeEnable = false;

    public MarqueeTextView(Context context) {
        this(context, null);
    }

    public MarqueeTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        /**
         * TextView.canMarquee() == false 时是不会滚动的
         * 一般原因是行数问题影响,导致宽度不合适,而android:lines是无效的
         *  focus 或者 selected状态才能跑马灯
         */

        setMaxLines(1);
        setSingleLine(true);

        if (isMarqueeEnable) {
            setMarqueeRepeatLimit(-1);
            setEllipsize(TextUtils.TruncateAt.MARQUEE);
        } else {
            setMarqueeRepeatLimit(0);
            setEllipsize(TextUtils.TruncateAt.END);
        }
        super.setSelected(isMarqueeEnable);
    }

    public void setMarqueeEnable(boolean enable) {
        if (isMarqueeEnable != enable) {
            isMarqueeEnable = enable;
            if (enable) {
                super.setSelected(true);
                setMarqueeRepeatLimit(-1);
                setEllipsize(TextUtils.TruncateAt.MARQUEE);
            } else {
                super.setSelected(false);
                setMarqueeRepeatLimit(0);
                setEllipsize(TextUtils.TruncateAt.END);
            }
        }
    }

    public boolean isMarqueeEnable() {
        return isMarqueeEnable;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!isMarqueeEnable) {
            return;
        }
        if (getLineCount() > 1) {
            Log.e(TAG, "the marquee will not work if  TextLineCount > 1");
        }
        if (getMarqueeRepeatLimit() <= 0) {
            Log.e(TAG, "the marquee may not work if  MarqueeRepeatLimit != -1");
        }
    }

    @Override
    public void setSelected(boolean selected) {
   //复写此方法,禁止外部调用,保证只有内部调用
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

三、宽度问题导致跑马灯跑不起来

经常能遇到layoutParams.width 为WRAP_CONTENT的情况,实际上这个原因并不是跑不起来的直接原因,因为wrap_content 本身导致宽度总是大于文本“宽度”,因此不要使用WRAP_CONTENT即可

 

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部