需求: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