Android自定义TextView实现文字自动滚动

效果:循环滚动,类似广告条

Android自定义TextView实现文字自动滚动_第1张图片

Android自定义TextView实现文字自动滚动_第2张图片

思路:

开启定时器刷新绘制文本的位置即可达到效果。

步骤1:新建ScrollTextView类继承自TextView。代码如下:

public class ScrollTextView extends TextView {

    private static final String TAG = "ScrollTextView";
    private String mText = "蒹葭苍苍,白露为霜。所谓伊人,在水一方。";
    private int mOffsetX = 0;
    private Rect mRect;
    private Timer mTimer;
    private TimerTask mTimerTask;
	
	    /**
     * 速度,负数左移,正数右移。
     */
    private int mSpeed = -10;
    private static final int PFS = 24;
	
    public ScrollTextView(Context context) {
        this(context, null);
    }
    public ScrollTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRect = new Rect();
        mTimer = new Timer();
        mTimerTask = new MyTimerTask();
        mTimer.schedule(mTimerTask, 0, 1000 / 24);
    }

    private class MyTimerTask extends TimerTask {
        @Override
        public void run() {
            //如果View能容下所有文字,直接返回
            if (mRect.right < getWidth()){
                return;
            }
            if (mOffsetX < - mRect.right - getPaddingEnd()){
                //左移时的情况
                mOffsetX = getPaddingStart();
            } else if (mOffsetX > getPaddingStart()){
                //右移时的情况
                mOffsetX = - mRect.right;
            }
            mOffsetX += mSpeed;
            postInvalidate();
        }
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取文本区域大小,保存在mRect中。
        getPaint().getTextBounds(mText, 0, mText.length(), mRect);
        if (mRect.right < getWidth()){
            canvas.drawText(mText, 0, getHeight() / 2, getPaint());
        }else {
            canvas.drawText(mText, mOffsetX, getHeight() / 2, getPaint());
        }
    }

    /**
     * 视图移除时销毁任务和定时器
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Log.e(TAG, "killTimer");
        if (mTimerTask != null){
            mTimerTask.cancel();
            mTimerTask = null;
        }
        if (mTimer != null){
            mTimer.cancel();
            mTimer = null;
        }
    }
}

完成上面代码可以的到如下效果:

Android自定义TextView实现文字自动滚动_第3张图片

以上是硬编码文字,如果尝试在XML布局或代码设置文字,将会显示的一塌糊涂:

    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ScrollTextView textView = findViewById(R.id.scrollTextView);
        textView.setText("开关磁阻电机的优缺点及使用");
    }

Android自定义TextView实现文字自动滚动_第4张图片

步骤2:需要对onDraw()做一些更改,如下:

    @Override
    protected void onDraw(Canvas canvas) {
        //此处去掉了super.onDraw(Canvas canvas);
        mText = getText().toString();
        TextPaint textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        //获取文本区域大小,保存在mRect中。
        textPaint.getTextBounds(mText, 0, mText.length(), mRect);
        if (mRect.right < getWidth()){
            canvas.drawText(mText, 0, getHeight() / 2, textPaint);
        }else {
            canvas.drawText(mText, mOffsetX, getHeight() / 2, textPaint);
        }
    }

一切都很正常,把字体调大再看看,发现并没有居中显示,而是稍稍偏上。

Android自定义TextView实现文字自动滚动_第5张图片

问题就在于:

canvas.drawText(mText, mOffsetX, getHeight() / 2, textPaint);

第三个参数,垂直方向的中点和文字的基准点并不重合。

Android自定义TextView实现文字自动滚动_第6张图片

图片引用自 android canvas drawText()文字居中   感谢原作,侵权立删。

需做如下计算: 

        float mTextCenterVerticalToBaseLine =
                ( - textPaint.ascent() + textPaint.descent()) / 2 - textPaint.descent();

这样就能文字居中了:

canvas.drawText(mText, mOffsetX, getHeight() / 2 + mTextCenterVerticalToBaseLine, textPaint);

Android自定义TextView实现文字自动滚动_第7张图片

别忘了在布局XML中设置单行显示,因为没有重写测量方法,布局使用wrap_content时得到的并不是我们想要的尺寸。

 android:maxLines="1"

到此就完成了。

最后附上完整代码:

自定义的ScrollTextView类:

public class ScrollTextView extends TextView {

    private static final String TAG = "ScrollTextView";
    private String mText = "蒹葭苍苍,白露为霜。所谓伊人,在水一方。";
    private int mOffsetX = 0;
    private Rect mRect;
    private Timer mTimer;
    private TimerTask mTimerTask;
    /**
     * 速度,负数左移,正数右移。
     */
    private int mSpeed = -10;
    private static final int PFS = 24;

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

    public ScrollTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRect = new Rect();
        mTimer = new Timer();
        mTimerTask = new MyTimerTask();
        //更新帧率24
        mTimer.schedule(mTimerTask, 0, 1000 / PFS);
    }

    private class MyTimerTask extends TimerTask {
        @Override
        public void run() {
            //如果View能容下所有文字,直接返回
            if (mRect.right < getWidth()){
                return;
            }
            if (mOffsetX < - mRect.right - getPaddingEnd()){
                //左移时的情况
                mOffsetX = getPaddingStart();
            } else if (mOffsetX > getPaddingStart()){
                //右移时的情况
                mOffsetX = - mRect.right;
            }
            mOffsetX += mSpeed;
            postInvalidate();
        }
    }
    @Override
    protected void onDraw(Canvas canvas) {
        //此处去掉了super.onDraw(Canvas canvas);
        mText = getText().toString();
        TextPaint textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        //获取文本区域大小,保存在mRect中。
        textPaint.getTextBounds(mText, 0, mText.length(), mRect);
        float mTextCenterVerticalToBaseLine =
                ( - textPaint.ascent() + textPaint.descent()) / 2 - textPaint.descent();
        if (mRect.right < getWidth()){
            canvas.drawText(mText, 0, getHeight() / 2 + mTextCenterVerticalToBaseLine, textPaint);
        }else {
            canvas.drawText(mText, mOffsetX, getHeight() / 2 + mTextCenterVerticalToBaseLine, textPaint);
        }
    }

    /**
     * 视图移除时销毁任务和定时器
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Log.e(TAG, "killTimer");
        if (mTimerTask != null){
            mTimerTask.cancel();
            mTimerTask = null;
        }
        if (mTimer != null){
            mTimer.cancel();
            mTimer = null;
        }
    }

    public void setSpeed(int speed){
        this.mSpeed = speed;
    }
}

MainActivity:

public class MainActivity extends Activity {

    String text1 = "桑之未落,其叶沃若。于嗟鸠兮,无食桑葚;\n" +
            "于嗟女兮,无与士耽。士之耽兮,犹可说也;\n" +
            "女之耽兮,不可说也。";

    String text2 = "桑之落矣,其黄而陨。自我徂尔,三岁食贫。\n" +
            "淇水汤汤,渐车帷裳。女也不爽,士贰其行。\n" +
            "士也罔极,二三其德。";

    String text3 = "三岁为妇,靡室劳矣;夙兴夜寐,靡有朝矣。\n" +
            "言既遂矣,至于暴矣。兄弟不知,咥其笑矣。\n" +
            "静言思之,躬自悼矣。";

    String text4 = "及尔偕老,老使我怨。淇则有岸,隰则有泮。\n" +
            "总角之宴,言笑晏晏。信誓旦旦,不思其反。\n" +
            "反是不思,亦已焉哉!";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ScrollTextView textView1 = findViewById(R.id.scrollTextView1);
        textView1.setText(text1);
        textView1.setSpeed(-5);

        ScrollTextView textView2 = findViewById(R.id.scrollTextView2);
        textView2.setText(text2);
        textView2.setSpeed(10);

        ScrollTextView textView3 = findViewById(R.id.scrollTextView3);
        textView3.setText(text3);
        textView3.setSpeed(-15);

        ScrollTextView textView4 = findViewById(R.id.scrollTextView4);
        textView4.setText(text4);
        textView4.setSpeed(20);
    }
}

布局文件activity_main.xml:




    

    

    

    

工程文件:

https://github.com/peoples-mountain-peoples-sea/ScrollText

你可能感兴趣的:(Android)