Android自定义textview实现自动滚动

一、背景

最近项目要实现一个置顶的子串滚动显示,类似广告条,需要悬浮在所有应用上面。

原本想直接使用Android TextView自带的Marquee效果,但是这个需要控件被选中才会执行跑马灯,而且要文本内容的宽度超出文本控件本身的宽度时才会执行,而项目需要的效果是不管文本内容有多少都要执行滚动效果,所以只能放弃。

最后改用自定义一个marqueetextview控件来实现自动跑马灯效果,参考了Android自定义TextView实现文字自动滚动_android textview自动滚动-CSDN博客的设计,不过原文章的设计还是要文本内容宽度超过控件宽度时才会触发滚动,所以在其基础上做了修改。

二、实现方案

整体思路:

1. 自定义一个AlwaysMarqueeTextView类继承TextView,添加一个定时器进行刷新文本的显示位置

2. 重写onDraw方法,根据文本的起始为mOffsetX进行重新绘制控件

3. 新加setMarqueeText(int resId)和setMarqueeText(CharSequence text)给外部调用,用于替换TextView的setText()方法


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class AlwaysMarqueeTextView extends TextView {

    private static final String TAG = "AlwaysMarqueeTextView";
    private int mOffsetX = 0;
    private Rect mRect;
    private String mText = "您的设备已过期,请尽快续费!";
    private Timer mTimer;
    private TimerTask mTimerTask;
    private int mTextWidth;

    private int mSpeed = 10;
    private static final int PFS = 24;

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

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

    public void setMarqueeText(CharSequence text) {
        setText(text);
        mText = text.toString();
        TextPaint textPaint = getPaint();
        textPaint.getTextBounds(mText, 0, mText.length(), mRect);
        mTextWidth = mRect.width();
    }

    public void setMarqueeText(int resId) {
        setText(resId);
        mText = getText().toString();
        TextPaint textPaint = getPaint();
        textPaint.getTextBounds(mText, 0, mText.length(), mRect);
        mTextWidth = mRect.width();
    }
    private class MyTimerTask extends TimerTask {
        @Override
        public void run() {
            if (mOffsetX < - (mTextWidth * 2) - getPaddingEnd()){
                mOffsetX = getWidth();
            }
            mOffsetX -= mSpeed;
            postInvalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mText = getText().toString();
        TextPaint textPaint = getPaint();
        textPaint.setColor(getCurrentTextColor());
        //获取文本区域大小,保存在mRect中。
        textPaint.getTextBounds(mText, 0, mText.length(), mRect);
        mRect.right = getWidth();//将绘画区域的右边设置为textview的宽度值
        float mTextCenterVerticalToBaseLine =
                ( - textPaint.ascent() + textPaint.descent()) / 2 - textPaint.descent();
        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;
    }
}

附带实现置顶自动滚动文本框的代码:

import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.TextView;
import com.xxx.example.R;

public class FloatMessageView {
    private  WindowManager windowManager;
    private  AlwaysMarqueeTextView txt_floatView;
    private  Context mContext;

    public FloatMessageView(Context context) {
        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mContext = context;
        createFloatView();
    }

    public void createFloatView() {
        int screenWidth = windowManager.getDefaultDisplay().getWidth();
        txt_floatView = new AlwaysMarqueeTextView(mContext);
        txt_floatView.setMarqueeText(R.string.message_device_outdated);
        txt_floatView.setBackgroundColor(Color.TRANSPARENT);
        txt_floatView.setTextColor(Color.RED);
        txt_floatView.setTextSize(28);
        txt_floatView.setSpeed(2);
        txt_floatView.setMaxLines(1);
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.gravity = Gravity.CENTER | Gravity.TOP;
        layoutParams.width = screenWidth / 2;
        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        layoutParams.y = 15;
        layoutParams.format = PixelFormat.RGBA_8888;
        txt_floatView.setLayoutParams(layoutParams);
        windowManager.addView(txt_floatView, layoutParams);
    }

    public void updateFloatMessage(CharSequence msg, int color) {
        txt_floatView.setTextColor(color);
        txt_floatView.setMarqueeText(msg);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,可以通过设置TextView的属性和使用一些代码来实现垂直自动滚动效果。 首先,我们可以使用xml布局文件或者代码动态创建一个TextView。在xml布局文件中,我们可以设置TextView的宽度和高度、文字内容等属性。 接下来,可以在代码中通过设置TextView的属性来实现垂直自动滚动。首先,我们可以使用setMaxLines方法来设置TextView的最大行数,让它只显示一行。然后,可以使用setEllipsize方法来设置TextView的省略方式为Marquee,表示文字超出一行时以滚动的形式显示。最后,再调用setSelected方法来启动滚动效果。 示例代码如下: ```java TextView textView = findViewById(R.id.text_view); textView.setMaxLines(1); textView.setEllipsize(TextUtils.TruncateAt.MARQUEE); textView.setSelected(true); ``` 这样,当TextView的文字内容超过一行时,就会自动滚动的方式显示。需要注意的是,在xml布局文件中或者代码中,需要将TextView的单行显示设置为true,并且保证TextView可获取焦点才能触发滚动效果。 除了上述方法,还可以使用属性动画或者使用Handler来实现TextView的垂直自动滚动效果。使用属性动画可以设置动画效果的速度和插值器,更加灵活。使用Handler的方式可以自定义滚动的速度和间隔时间。 总之,通过设置TextView的属性和使用一些代码,我们可以实现AndroidTextView的垂直自动滚动效果,提升用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值