最近项目中用到了 横向跑马灯 顺序显示list 中的数据,并且增加每个的点击事件
ViewFlipper 虽然能很好的实现跑马灯功能,但是如果只显示一行,设置 singleLine = true时,只要内容过长,就会显示不全,所有最后在我以前写的基础上做了部分修改。
废话不多说,上代码:
public class MuchMarqueeView extends AppCompatTextView {
private float textLength = 0f;// 文本长度
private float viewWidth = 0f;
private float step = 0f;// 文字的横坐标
private float y = 0f;// 文字的纵坐标
private float temp_view_plus_text_length = 0.0f;// 用于计算的临时变量 ,第一条数据要划出屏幕的长度
private float temp_view_plus_two_text_length = 0.0f;// 用于计算的临时变量,第二跳数据开始滑动进入屏幕的长度
public boolean isStarting = false;// 是否开始滚动
private Paint paint = null;// 绘图样式
private String text = "";// 文本内容
private float currentScrollX;// 当前滚动的位置
private float lastIndex = 0f;//上一次滚动的位置
private List<Information> informationList = new ArrayList<>();
private int marqueeIndex = 0;
private WindowManager windowManager;
private OnMarqueeItemListener marqueeItemListener;
//由第一个item 切换到第二个item 的时间,
private long switchSecondTime = 0;
public void setWindowManager(WindowManager windowManager) {
this.windowManager = windowManager;
}
//更新list后,从第1条重新开始
public void setStrings(List<Information> strings) {
this.informationList = strings;
marqueeIndex = 0;
}
public void setMarqueeItemListener(OnMarqueeItemListener marqueeItemListener) {
this.marqueeItemListener = marqueeItemListener;
}
public MuchMarqueeView(Context context) {
this(context, null);
}
public MuchMarqueeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MuchMarqueeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOnClickListener(v -> {
if (marqueeItemListener != null) {
marqueeItemListener.onItemListener(marqueeIndex);
}
});
}
/**
* 开始滚动
*/
public void startScroll() {
if (!isStarting) {
try {
isStarting = true;
setViewText();
invalidate();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 停止滚动
*/
public void stopScroll() {
if (isStarting) {
try {
isStarting = false;
invalidate();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void setViewText() {
if (marqueeIndex == informationList.size()) {
marqueeIndex = 0;
}
setTextContent(informationList.get(marqueeIndex).informationTitle);
}
public void setTextContent(String text) {
setText(text);
init();
}
/**
* 文本初始化,每次更改文本内容或者文本效果等之后都需要重新初始化一下
*/
public void init() {
try {
paint = getPaint();
paint.setColor(Color.parseColor("#424242"));
paint.setTextSize(UIUtils.dip2px(getContext(), 16));
text = getText().toString();
textLength = paint.measureText(text);
viewWidth = getWidth();
if (viewWidth == 0) {
if (windowManager != null) {
Display display = windowManager.getDefaultDisplay();
viewWidth = display.getWidth();
}
}
if (marqueeIndex == 0) {
step = textLength;
temp_view_plus_text_length = textLength;
temp_view_plus_two_text_length = textLength * 2;
} else {
step = textLength;
temp_view_plus_text_length = viewWidth + textLength;
temp_view_plus_two_text_length = viewWidth + textLength * 2;
}
y = getTextSize() + getPaddingTop();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDraw(Canvas canvas) {
try {
lastIndex = currentScrollX;
canvas.drawText(text, temp_view_plus_text_length - step, y, paint);
currentScrollX = temp_view_plus_text_length - step;
//重点,通过滚动的坐标,来判断一条数据是否完全消失,
//由于第一条数据是据靠左显示并移动的,所以当第一条切换到第二条数据时,
// lastIndex < 0 和 currentScrollX >= 0 本身就成立,所以增加一个时间判断
if (lastIndex < 0 && currentScrollX >= 0 && System.currentTimeMillis() - switchSecondTime > 200) {
marqueeIndex++;
setViewText();
}
if (step - temp_view_plus_text_length * 2 == 0) {
marqueeIndex++;
switchSecondTime = System.currentTimeMillis();
setViewText();
}
if (!isStarting) {
return;
}
step += 3;// 速度
if (step > temp_view_plus_two_text_length) {
step = textLength;
}
invalidate();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean isFocused() {
return true;
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (focused) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if (hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
}
}
public interface OnMarqueeItemListener {
void onItemListener(int position);
}
}