首页 > 其他分享 >自定义TextView实现首尾相接跑马灯效果

自定义TextView实现首尾相接跑马灯效果

时间:2024-08-30 10:24:02浏览次数:6  
标签:滚动 自定义 int void 跑马灯 import android public TextView

需求:TextView内容不满一行的时候不滚动,超过一行的时候缓慢滚动到最后,然后添加空白间隔继续滚动

(我们项目用的是三个View一块滚动,停止应该是不一块停止的,毕竟三条内容应该不一样长,所以就需要个监听是否都停止了,如果都停止了,就一块开启继续滚动)

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.umeng.commonsdk.debug.E;

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;
    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() {
        paint.setColor(Color.parseColor("#535353"));
        paint.setTextSize(17);
        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变化之前
         */
        int time = scrollDistance/100;
        scrollDistance = lastScrollX + scrollDistance;
        // 创建ValueAnimator
        animator = ValueAnimator.ofInt(lastScrollX, scrollDistance);
        // 设置动画的持续时间
        animator.setDuration(time*1000); // 500毫秒

        // 设置插值器,这里使用默认的(线性插值器),但你可以根据需要更改
        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();
        isScrolling = false;
        if(animator!=null){
            animator.pause();
        }
    }

    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);
    }

}

继续滚动方法setNextScrollTextMessage

单条的滚动没问题,多条第二次同时滚动的时候应该是多少有一点点的延迟的,会造成头部不对齐问题,待优化

标签:滚动,自定义,int,void,跑马灯,import,android,public,TextView
From: https://blog.csdn.net/csdn_zxw/article/details/141706587

相关文章

  • 金蝶云星空组织间结算清单增加自定义字段说明
    单据增加字段相关结算单增加,基础资料控件,映射资料。 业务单据-其他出库单增加字段 配置功能特性   创建结算清单时,会生成到自定义字段上      ......
  • 鸿蒙HarmonyOS自定义组件开发和使用_鸿蒙自定义组件
    自定义组件的介绍在开发和使用自定义组件直接,我们需要了解什么是自定义组件?在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行UI界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后......
  • net core自定义 Configuration Provider
    创建CustomConfigurationProvider首先,我们需要创建一个自定义的ConfigurationSource和ConfigurationProvider来支持配置文件的读取和监控。publicclassCustomConfigurationSource:IConfigurationSource{publicstringFilePath{get;}publicCustomConfig......
  • 网络防火墙之自定义chain
    网络防火墙自定义链链管理:-N:new,自定义一条新的规则链-X:delete,删除自定义的空的规则链-P:Policy,设置默认策略;对filter表中的链而言,其默认策略有:ACCEPT:接受DROP:丢弃-E:重命名自定义链;引用计数不为0的自定义链不能够被重命名,也不能被删除 ......
  • Java-List结合ComableFuture自定义线程池的工具类
    为了结合CompletableFuture处理列表中的数据,并利用自定义线程池来并行处理这些元素,我们可以创建一个工具类ListCompletableFutureUtil,它包含一个静态方法processListConcurrently,该方法接收一个列表、一个处理每个元素的函数以及一个自定义线程池,并利用CompletableFutur......
  • 洛雪音乐限定复活 - 自定义音源
    洛雪音乐之前因为被发了绿师函所以软件本身不再提供各大平台的接口,但是保留了自定义音源的功能,目前还能支持播放缓存下载功能。感谢sixyin为广大网友做出的贡献。下面简单介绍一下使用方法:Step1准备文件下载并安装洛雪音乐(lx-music-desktop)[官方页面]|[下载链接]下......
  • go 结构体切片自定义排序
    常见类型的默认实现gosort包默认支持int(sort.Ints(x[]int))、float64s(sort.Float64s(x[]float64))、string(sort.Strings(x[]string))从小到大排序,反序使用类似于sort.Sort(sort.Reverse(sort.Ints(x[]int)))的方式。结构体切片的自定义实现packagemainimport( "fmt" "s......
  • IEnumrable接口 GetEnumerator方法 foreach 遍历 自定义 迭代器
    **能用foreach遍历访问的对象需要实现什么接口或声明什么方法**要使用foreach循环,对象必须实现IEnumerable接口或者声明GetEnumerator方法。解释IEnumerable接口:这个接口定义了一个名为GetEnumerator的方法,该方法返回一个枚举器,允许客户端代码逐个访问集合......
  • CI3自定义类库,并传参
    1、创建类文件 2、构造函数中使用数组形参,接收传递参数classHehe{//------------------------------------------------------------------------publicfunction__construct($config=array()){p($config);}//-------------------------------......
  • CAS server如何自定义Controller控制器
    CASserver如何自定义Controller控制器在实际开发过程中,CASServer4.0.0服务端提供了登录、认证等功能,但是我们希望加入更多的自定义功能,如自定义第三方登录服务等功能。增加一个Controller类控制器以及修改部分配置来完成CASServer4.0.0自定义Controller扩展,废话就不多说了,......