TextView 跑马灯效果 文字内容长度大于控件自身宽度时候,开启跑马灯效果
public class AutoPollTextView extends View {
private int textColor;
private int textSize;
private Rect rect;
private TextPaint paint;
private String contentStr = "";
private String showContentStr = "";
private Marquee mMarquee;
private float textHeight;
private int textWidth;
public void setText(String text, String tag) {
if (tag != null && !tag.equals(getTag())) {
text = text == null ? "" : text;
if (!contentStr.equals(text)) {
contentStr = text;
}
invalidate();
}
}
public static final class Marquee {
private static final int MARQUEE_DELAY = 0;
private static final byte MARQUEE_STOPPED = 0x0;
private static final byte MARQUEE_STARTING = 0x1;
private static final byte MARQUEE_RUNNING = 0x2;
private final WeakReference<AutoPollTextView> mView;
private final Choreographer mChoreographer;
private byte mStatus = MARQUEE_STOPPED;
private final float mPixelsPerMs = 1f;
private float mMaxScroll;
private float mGhostStart;
private float mScroll;
private String blackStr = "";
public Marquee(AutoPollTextView view) {
this.mView = new WeakReference<>(view);
mChoreographer = Choreographer.getInstance();
}
private Choreographer.FrameCallback mTickCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
tick();
}
};
private Choreographer.FrameCallback mStartCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
mStatus = MARQUEE_RUNNING;
tick();
}
};
private Choreographer.FrameCallback mRestartCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
if (mStatus == MARQUEE_RUNNING) {
start();
}
}
};
void tick() {
if (mStatus != MARQUEE_RUNNING) {
return;
}
mChoreographer.removeFrameCallback(mTickCallback);
final AutoPollTextView textView = mView.get();
if (textView != null) {
float deltaPx = mPixelsPerMs * 1;
mScroll += deltaPx;
if (mScroll > mMaxScroll) {
mScroll = 0.0f;
mChoreographer.postFrameCallbackDelayed(mRestartCallback, MARQUEE_DELAY);
} else {
mChoreographer.postFrameCallback(mTickCallback);
}
textView.invalidate();
}
}
void stop() {
mStatus = MARQUEE_STOPPED;
mChoreographer.removeFrameCallback(mStartCallback);
mChoreographer.removeFrameCallback(mRestartCallback);
mChoreographer.removeFrameCallback(mTickCallback);
}
void start() {
final AutoPollTextView textView = mView.get();
if (textView != null) {
mStatus = MARQUEE_STARTING;
// mScroll = 0.0f;
final int textWidth = textView.getWidth();
final float lineWidth = textView.textWidth();
final float gap = textWidth / 3.0f;
mGhostStart = lineWidth - textWidth + gap;
mMaxScroll = mGhostStart + textWidth;
textView.invalidate();
mChoreographer.postFrameCallback(mStartCallback);
}
}
public String textWidthStr() {
String textBlackStr = "";
if (mView != null) {
final AutoPollTextView textView = mView.get();
if (textView != null) {
float l = textView.getWidth() / 3f;
float c = textView.contentWidthHeight();
int f = (int) ((int) l / c);
for (int w = 0; w < f; w++) {
textBlackStr = textBlackStr + " ";
}
}
}
return textBlackStr;
}
String getBlackStr() {
if (blackStr != null && blackStr.length() > 0) {
return blackStr;
}
blackStr = textWidthStr();
return blackStr;
}
float getScroll() {
return mScroll;
}
boolean isRunning() {
return mStatus == MARQUEE_RUNNING;
}
boolean isStopped() {
return mStatus == MARQUEE_STOPPED;
}
}
public AutoPollTextView(Context context) {
this(context, null);
}
public AutoPollTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoPollTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoPollTextView);
textColor = a.getColor(R.styleable.AutoPollTextView_ap_text_color, Color.parseColor("#f21646"));
textSize = a.getDimensionPixelOffset(R.styleable.AutoPollTextView_ap_text_size, dp2px(12));
a.recycle();
rect = new Rect();
paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);//初始化文本画笔
paint.setStyle(Paint.Style.FILL);
paint.setColor(textColor);//文字颜色值,可以不设定
paint.setTextSize(textSize);//文字大小
mMarquee = new Marquee(this);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
startStopMarquee(hasWindowFocus);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
startStopMarquee(visibility == View.VISIBLE);
}
private void startStopMarquee(boolean start) {
if (start) {
startMarquee();
} else {
stopMarquee();
}
}
private void stopMarquee() {
if (mMarquee != null && !mMarquee.isStopped()) {
mMarquee.stop();
}
}
@Override
protected void onDraw(Canvas canvas) {
restartMarqueeIfNeeded();
super.onDraw(canvas);
if (compressText(getWidth()) && mMarquee != null) {
if (!showContentStr.equals(contentStr)) {
showContentStr = contentStr + mMarquee.getBlackStr() + contentStr;
}
canvas.drawText(showContentStr, -mMarquee.getScroll(), getHeight() / 2 + textHeight / 2, paint);
} else {
canvas.drawText(contentStr, (getWidth() - textWidth) / 2, getHeight() / 2 + textHeight / 2, paint);
}
}
private void restartMarqueeIfNeeded() {
startMarquee();
}
private void startMarquee() {
// Do not ellipsize EditText
if (!compressText(getWidth())) {
return;
}
if (mMarquee == null) mMarquee = new Marquee(this);
if (!mMarquee.isRunning()) {
mMarquee.start();
}
}
public boolean compressText(float width) {
if (rect == null) {
rect = new Rect();
}
paint.getTextBounds(contentStr, 0, contentStr.length(), rect);
textHeight = getContentHeight();
textWidth = rect.width();
return rect.width() > width;
}
public float textWidth() {
return textWidth;
}
private float getContentHeight() {
if (paint != null) {
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
return Math.abs((fontMetrics.bottom - fontMetrics.top)) / 2;
}
return dp2px(30);
}
private float contentWidthHeight() {
String text1 = "en en";
String text2 = "enen";
return contentWidth(text1) - contentWidth(text2);
}
private float contentWidth(String black) {
if (black == null || black == "") {
return 0;
}
if (rect == null) {
rect = new Rect();
}
paint.getTextBounds(black, 0, black.length(), rect);
textHeight = getContentHeight();
return rect.width();
}
public int dp2px(float dpValue) {
final float scale = getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}