public class VerticalMarqueeView extends View {
// 滚动时间
public static final int DURATION_SCROLL = 3000;
// 动画时间
public static final int DURATION_ANIMATOR = 1000;
// 广告颜色
private int color = Color.BLACK;
private int textSize = 30;
// 广告行数
private int row = 1;
// 数据源
private ArrayList<String> datas = new ArrayList<>();
// 当前点击的位置
private int index = 0;
private int width;
private int height;
private int centerX;
private int centerY;
private List<TextBlock> blocks = new ArrayList<TextBlock>();
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Handler handler = new Handler();
private boolean isStopScroll = true;
// 控制滚动的Runnable
private Runnable runnable;
public VerticalMarqueeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public VerticalMarqueeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalMarqueeView(Context context) {
super(context);
}
public VerticalMarqueeView color(int color) {
this.color = color;
return this;
}
public VerticalMarqueeView textSize(int textSize) {
this.textSize = textSize;
return this;
}
public VerticalMarqueeView datas(ArrayList<String> data) {
LogUtils.d("传输大小--》" + data.size());
this.blocks.clear();
this.datas.clear();
this.datas.addAll(data);
return this;
}
public ArrayList<String> getDatas() {
return datas;
}
public VerticalMarqueeView row(int row) {
this.row = row;
return this;
}
public void commit() {
if (this.datas == null || datas.size() == 0) {
Log.e("VerticalMarqueeView", "the datas's length is illegal");
throw new IllegalStateException("may be not invoke the method named datas(String[])");
}
paint.setColor(color);
paint.setTextSize(textSize);
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (this.datas == null || this.datas.size() == 0) {
Log.e("VerticalMarqueeView", "the datas's length is illegal");
return;
}
if (datas.size() < row) {
Log.e("VerticalMarqueeView", "行数不能大于数据大小");
return;
}
width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
// 计算每一项的高
height = (MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom()) / row;
// 如果需要居中,这里除以2
centerX = width / 2;
centerY = height / 2;
blocks.clear();
//添加显示区域的文字块
for (int i = 0; i <= row; i++) {
TextBlock block = new TextBlock(width, height, paint);
block.reset(datas.get(i), centerX, centerY + height * i, i);
blocks.add(block);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
LogUtils.d("高:" + getHeight() + "Y:" + event.getY() + "position:" + (event.getY() / ((getHeight() - row) / row)));
index = (int) (event.getY() / ((getHeight() - row) / row));
break;
case MotionEvent.ACTION_UP:
if (listener != null) {
listener.onItemClick(blocks.get(index)
.getPosition());
}
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < blocks.size(); i++) {
blocks.get(i)
.draw(canvas);
}
}
public void startScroll() {
isStopScroll = false;
if (datas == null || datas.size() == 0 || datas.size() == 1) {
Log.e("VerticalMarqueeView", "the datas's length is illegal");
return;
}
if (!isStopScroll) {
if (runnable == null) {
runnable = new Runnable() {
@Override
public void run() {
scroll();
if (!isStopScroll) {
handler.postDelayed(this, DURATION_SCROLL);
}
}
};
handler.postDelayed(runnable, DURATION_SCROLL);
}
}
}
public boolean isStopScrolling() {
return isStopScroll;
}
public void stopScroll() {
this.isStopScroll = true;
}
private void scroll() {
LogUtils.d("滚动");
ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder.ofInt("scrollY", centerY, centerY - height));
animator.setDuration(DURATION_ANIMATOR);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int scrollY = (int) animation.getAnimatedValue("scrollY");
for (int i = 0; i < blocks.size(); i++) {
blocks.get(i)
.reset(scrollY + height * i);
}
invalidate();
}
});
animator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (blocks.size() == 0) {
return;
}
//移除第一块
int position = blocks.get(row)
.getPosition();
TextBlock textBlock = blocks.remove(0);
//最后一个
if (position == datas.size() - 1) {
position = 0;
} else {
position++;
}
textBlock.reset(datas.get(position), centerY + height * (position + row), position);
blocks.add(textBlock);
invalidate();
}
@Override
public void onAnimationCancel(Animator animation) {
}
});
animator.start();
}
public int getCurrentPosition() {
if (datas == null || datas.size() == 0) {
return -1;
}
if (datas.size() == 1 && blocks.size() == 1) {
return 0;
}
return blocks.get(0)
.getPosition();
}
public class TextBlock {
private int width;
private int height;
private String text;
private int drawX;
private int drawY;
private int pointDrawX;
private int pointDrawY;
private Paint paint;
private Paint pointPaint;
private int position;
public TextBlock(int width, int height, Paint paint) {
this.width = width;
this.height = height;
this.paint = paint;
this.pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
pointPaint.setColor(paint.getColor());
pointPaint.setTextSize(paint.getTextSize());
}
public void reset(int centerY) {
reset(text, centerX, centerY, position);
}
public void reset(String text, int centerY) {
reset(text, centerX, centerY, position);
}
public void reset(String text, int centerY, int position) {
reset(text, centerX, centerY, position);
}
public void reset(String text, int centerX, int centerY, int position) {
this.text = text;
this.position = position;
// 先绘制点•
int pointWidth = (int) pointPaint.measureText("•");
pointDrawX = 0;
FontMetrics pointMetrics = pointPaint.getFontMetrics();
pointDrawY = (int) (centerY + (pointMetrics.bottom - pointMetrics.top) / 2 - pointMetrics.bottom);
// 绘制正文
int measureWidth = (int) paint.measureText(text);
// 当文字长度超过控件宽度,截取文字,并添加省略号
if (!TextUtils.isEmpty(text)) {
float textWidth = paint.measureText(text);
if (textWidth > width) {
int subIndex = paint.breakText(text, 0, text.length(), true, width, null);
this.text = text.substring(0, subIndex - 2) + "...";
}
}
// 居中
// drawX = (width - measureWidth) / 2;
// 左侧对齐
drawX = (int) pointPaint.measureText("0");
FontMetrics metrics = paint.getFontMetrics();
drawY = (int) (centerY + (metrics.bottom - metrics.top) / 2 - metrics.bottom);
}
public int getPosition() {
return position;
}
public void draw(Canvas canvas) {
canvas.drawText("•", pointDrawX, pointDrawY, pointPaint);
canvas.drawText(text, drawX, drawY, paint);
}
@Override
public String toString() {
return "TextBlock{" + "width=" + width + ", height=" + height + ", text='" + text + '\'' + ", drawX=" + drawX + ", drawY=" + drawY + ", pointDrawX=" + pointDrawX + ", pointDrawY=" + pointDrawY + ", paint=" + paint + ", pointPaint=" + pointPaint + ", position=" + position + '}';
}
}
private OnItemClickListener listener;
public OnItemClickListener getOnItemClickListenerr() {
return listener;
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
}
锤子滚动的textview
最新推荐文章于 2020-07-17 17:07:09 发布