Android系统TextView跑马灯限制过多(需有焦点和文字超长)
设置步长(滚动速度)即可滚动
public class MarqueeTextView extends AppCompatTextView {
private static final int PFS = 24;//刷新率
private int textWidth;//文字长度
private int mStep = -5;//速度,负数左移,正数右移。
private int mOffsetX = 0;//偏移量
private int mDistance = 100;//文件重复出现间距
private Timer mTimer;//定时器
private Rect mTextRect;//文字占位矩阵
private TimerTask mTimerTask;//定时任务
private boolean isPressPause = true;//是否按压暂停
private boolean isStop = false;
private boolean isSingle = false;
public MarqueeTextView(Context context) {
this(context, null);
}
public MarqueeTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mTextRect = new Rect();
mTimer = new Timer();
mTimerTask = new ScrollTask();
mTimer.schedule(mTimerTask, 0, 1000 / PFS);
setDistance(100);
setSingle(false);
}
public MarqueeTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
private class ScrollTask extends TimerTask {
@Override
public void run() {
if (mStep != 0 && !isStop) {
mOffsetX += mStep;
int maxW = textWidth + mDistance;
mOffsetX = mOffsetX % (maxW);
postInvalidate();
}
}
}
@Override
protected void onDraw(Canvas canvas) {
if (mStep == 0) {
super.onDraw(canvas);
} else {
String mText = getText().toString();
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.getTextBounds(mText, 0, mText.length(), mTextRect);
float mTextCenterVerticalToBaseLine =
(-textPaint.ascent() + textPaint.descent()) / 2 - textPaint.descent();
int width = getWidth();
textWidth = mTextRect.width();
boolean isLeft = mStep < 0;
float y = (getHeight() >> 1) + mTextCenterVerticalToBaseLine;
if (isSingle) {
mDistance = width;
canvas.drawText(mText, mOffsetX + (isLeft ? mDistance : -textWidth), y, textPaint);
} else {
int w = textWidth + mDistance;
int size = width / w + 1;
canvas.drawText(mText, mOffsetX + (isLeft ? 0 : width - textWidth), y, textPaint);
for (int i = 1; i <= size; i++) {
int offset = w * i;
canvas.drawText(mText, mOffsetX + (isLeft ? offset : width - textWidth - offset), y, textPaint);
}
}
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isPressPause && event != null) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setStop(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
setStop(false);
break;
}
return true;
}
return super.onTouchEvent(event);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
mTextRect = null;
}
public void setStep(int step) {
mOffsetX = 0;
mStep = step;
postInvalidate();
}
public int getStep() {
return mStep;
}
public void setDistance(int distance) {
if (!isSingle){
mDistance = distance;
lastDistance = mDistance;
}
}
public void setPressPause(boolean isPressPause) {
this.isPressPause = isPressPause;
}
public void setStop(boolean stop) {
isStop = stop;
}
private int lastDistance = 0;
public void setSingle(boolean single) {
mOffsetX = 0;
isSingle = single;
if (single) {
lastDistance = mDistance;
} else {
mDistance = lastDistance;
}
postInvalidate();
}
public boolean isStop() {
return isStop;
}
public boolean isSingle() {
return isSingle;
}
}
1、布局文件
2、Activity
public class MainActivity extends AppCompatActivity {
private TextView tvStep;
private MarqueeTextView tv_1;
private MarqueeTextView tv_2;
private TextView tvDistance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_1 = findViewById(R.id.marquee_tv_1);
tv_2 = findViewById(R.id.marquee_tv_2);
tv_2.setSingle(true);
Button btnSingle = findViewById(R.id.btn_single);
btnSingle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setSingle();
}
});
SeekBar seekStep = findViewById(R.id.seek_step);
SeekBar seekDistance = findViewById(R.id.seek_distance);
tvStep = findViewById(R.id.tv_step);
tvDistance = findViewById(R.id.tv_distance);
seekDistance.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
setDistance(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
seekStep.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
setStep(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
public void setStep(int step) {
tvStep.setText(String.valueOf(step));
tv_1.setStep(step);
tv_2.setStep(step);
}
public void setSingle() {
tv_1.setSingle(!tv_1.isSingle());
tv_2.setSingle(!tv_2.isSingle());
}
public void setDistance(int distance) {
tvDistance.setText(String.valueOf(distance));
tv_1.setDistance(distance);
tv_2.setDistance(distance);
}
}