自定义TextView实现首尾相接多行跑马灯等待效果

需求:三行跑马灯自己跑自己的,但是短的需要等长的结束后再一块启动一块跑,一听这需求脑袋都大了,所以出来了这第二个版本,在第一个版本(自定义TextView实现首尾相接跑马灯效果-CSDN博客)的基础上改良了一下,如果只是拿第一个版本来实现,会出现短的跑的快问题,后来想了想,应该跟长度有关,这里精确一点应该问题不大

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;

import androidx.appcompat.widget.AppCompatTextView;

import com.blankj.utilcode.util.ScreenUtils;
import com.iqilu.core.CoreStringType;
import com.umeng.commonsdk.debug.E;

import java.text.DecimalFormat;

public class AutoScrollTextViewNew extends AppCompatTextView {
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private boolean isScrolling = false;
    /**
     * 最大可滚动距离
     */
    private int maxScrollX;
    private String showMessage = "";
    private ValueAnimator animator;
    private ScrollStatus scrollStatus;
    /**
     * 空格
     */
    private String Space = "         ";
    /**
     * scrollX每次移动的坐标
     * lastScrollX最后移动的坐标
     */
    private int scrollX = 0,lastScrollX = 0;
    /**
     * 滚动速度,数值越大,速度越快
     */
    private double scrollNumber = 150.00;
    /**
     * 字体大小
     */
    private int textSize = CoreStringType.SEVENTEEN;
    private DecimalFormat df;
    private boolean isDetachedFromWindow = false;
    public AutoScrollTextViewNew(Context context) {
        super(context);
        init();
    }

    public AutoScrollTextViewNew(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AutoScrollTextViewNew(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        df = new DecimalFormat("#.00");
        paint.setColor(Color.parseColor("#535353"));
        paint.setTextSize(textSize);
        paint.setTextAlign(Paint.Align.LEFT);
        setSingleLine(true); // 设置单行模式
        // 监听布局变化,以便在布局完成后计算最大滚动距离
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (getLayout() != null) {
                    // 计算最大滚动距离
                    int textWidth = (int) getPaint().measureText(showMessage);
                    int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
                    maxScrollX = Math.max(0, textWidth - viewWidth);

                    // 如果内容超出视图宽度,则开始滚动
                    if (maxScrollX > 0 && !isScrolling) {
                        startScrolling(maxScrollX);
                    }else {
                        scrollStatus.putScrollStatus(showMessage);
                    }
                    // 移除监听器,避免重复调用
                    getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            }
        });
    }

    private void startScrolling(int scrollDistance) {
        /**
         * 这里必须减掉本身的宽度,如果不减,lastScrollX会越来越大,速度就会越来越慢
         */
        if(lastScrollX>scrollDistance){
            lastScrollX = lastScrollX - scrollDistance;
        }
        /**
         * 时间不能变,时间要在scrollDistance变化之前
         */
        Log.e("11111111tscrollDistance",scrollDistance+"");
        double time = Double.parseDouble(df.format((double)(scrollDistance/scrollNumber)));
        Log.e("11111111time",time+"");
        scrollDistance = lastScrollX + scrollDistance;
        // 创建ValueAnimator
        animator = ValueAnimator.ofInt(lastScrollX, scrollDistance);
        // 设置动画的持续时间
        animator.setDuration((long) (time*1000));

        // 设置插值器,这里使用默认的(线性插值器),但你可以根据需要更改
        animator.setInterpolator(new LinearInterpolator());

        // 添加更新监听器,在动画的每一帧中更新TextView的滚动位置
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                lastScrollX = scrollX;
                scrollStatus.putScrollStatus(showMessage);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animator.addUpdateListener(animation -> {
            scrollX = (int) animation.getAnimatedValue();
            setScrollX(scrollX);
        });

        // 开始动画
        animator.start();

    }


    // 确保在视图不再需要时停止滚动
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        isDetachedFromWindow = true;
        isScrolling = false;
        if(animator!=null){
            animator.pause();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if(isDetachedFromWindow){
            isScrolling = true;
            setNextScrollTextMessage();
            isDetachedFromWindow = false;
        }
    }

    public void setShowText(String message, ScrollStatus scrollStatus){
        this.showMessage = message;
        setText(message);
        this.scrollStatus = scrollStatus;
    }

    /**
     * 设置接下来需要滚动的内容以及距离
     */
    public void setNextScrollTextMessage(){
        if(maxScrollX > 0){
            append(Space+showMessage);
            int textSize = (int) getPaint().measureText(Space);
            int textWidth = (int) getPaint().measureText(showMessage);
            int allWidth = textWidth+textSize;
            startScrolling(allWidth);
        }else {
            scrollStatus.putScrollStatus(showMessage);
        }
    }

    public interface ScrollStatus{
        void putScrollStatus(String message);
    }

}

使用也简单

textViewNewThree.setShowText(messageList.get(2).getTitle(), new AutoScrollTextViewNew.ScrollStatus() {
    @Override
    public void putScrollStatus(String message) {
        allMessage.add(message);
        if(allMessage.size()==messageList.size()){
            allMessage.clear();
            textViewNewOne.setNextScrollTextMessage();
            textViewNewTwo.setNextScrollTextMessage();
            textViewNewThree.setNextScrollTextMessage();
        }
    }
});

allMessage存储的就是当前滚动的内容,如果存储长度跟当前的List内容一样多,说明都滚动了,就可以进行下一轮的滚动了

具体的方法说明我已经加了备注,方便日后自己翻阅

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

csdn_zxw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值