自定义View实现文本水平方向的跑马灯效果,可以设置文本相关属性及滚动速度,以及滚动方式
/**
* Created by wyl on 2018/10/10.
*/
public class MarqueeView extends View {
private static final String TAG = " MarqueeView ";
private final float DEF_SIZE = 250.0f;//默认字体大小
private final int DEF_COLOR = 0xff0000;
private float mSpeed = 4.0F; //默认滚动速度
private boolean isScroll = true; //是否自动滚动
private Context mContext;
private Paint mPaint; //文字画笔
private String mText;//展示内容
private float mCoordinateX;//文字起始位置的X轴偏移量
private float mCoordinateX_;//首尾紧跟滚动 新一轮文字起始位置的X轴偏移量
private float mCoordinateY;//Y轴偏移量
private float mTextWidth; //文本的宽度
private int mViewWidth; //控件的宽度
private int mViewHeight;//控件高度
public static int SCROLL_ENDED = 1, SCROLL_FOLLOW = 2;
private int mScrollType;//文本滚动方式 紧邻滚动、一行结束之后滚动
private int mFollowSpace = 10;//相邻滚动 首尾文字间距
public MarqueeView(Context context) {
super(context);
init(context);
}
public MarqueeView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MarqueeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
this.mContext = context;
if (TextUtils.isEmpty(mText)) {
mText = "欢迎光临";
}
mPaint = new Paint();
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
mPaint.setAntiAlias(true);
mPaint.setTextSize(DEF_SIZE);
mPaint.setColor(DEF_COLOR);
}
public void setText(String text) {
mText = text;
if (TextUtils.isEmpty(mText)) {
mText = "欢迎光临!";
}
requestLayout();//设置字体过后 需要重新测量View
invalidate();//重新绘制
}
public void setTextSize(float textSize) {
mPaint.setTextSize(textSize <= 0 ? DEF_SIZE : textSize);
requestLayout();
invalidate();
}
public void setTextColor(int textColor) {
mPaint.setColor(textColor);
invalidate();
}
//设置滚动速度
public void setTextSpeed(float speed) {
this.mSpeed = speed < 1 ? 1 : speed;
invalidate();
}
/**
* //设置滚动相邻距离
* //根据控件宽度设置最好
*
* @param space
*/
public void setFollowSpace(int space) {
this.mFollowSpace = space < 10 ? 10 : space;
invalidate();
}
//设置滚动方式
public void setScrollType(int type) {
mScrollType = type;
invalidate();
}
//设置滚动
public void setScroll(boolean isScroll) {
this.isScroll = isScroll;
invalidate();
}
//是否滚动
public boolean isScroll() {
return isScroll;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCoordinateX = getWidth();
mCoordinateX_ = mCoordinateX;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mTextWidth = mPaint.measureText(mText);//测量文本长度
//从屏幕最右端开始
// mCoordinateX = getResources().getDisplayMetrics().widthPixels;
//测量控件宽度
mViewWidth = measureW(widthMeasureSpec);
//测量控件高度
mViewHeight = measureH(heightMeasureSpec);
//测量文本起始位置Y轴的偏移量 使其水平居中
Paint.FontMetricsInt fm = mPaint.getFontMetricsInt();
mCoordinateY = getHeight() / 2 - fm.descent + (fm.descent - fm.ascent) / 2;
//根据文本显示内容选择
//----------------------top
//----------------------ascent
// 内容(中文/英文)
//----------------------baseline
//----------------------descent
//----------------------bottom
//mCoordinateY = getHeight() / 2 - fm.descent + (fm.bottom- fm.top) / 2
mCoordinateX = mViewWidth;
mCoordinateX_ = mCoordinateX;
setMeasuredDimension(mViewWidth, mViewHeight);
}
private int measureW(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {//match_parent 或者 具体的值
result = specSize;
} else {//wrap_content 由文本长度 及左右padding决定
result = (int) mPaint.measureText(mText) + getPaddingLeft()
+ getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private int measureH(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {//match_parent 或者 具体的值
result = specSize;
} else {//wrap_content 控件高度由字体大小 及 上下padding决定
result = (int) mPaint.getTextSize() + getPaddingTop()
+ getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if ((Math.abs(mCoordinateX) > mTextWidth && mCoordinateX < 0)) {
mCoordinateX = mCoordinateX_;
mCoordinateX_ = getWidth();
}
Paint.FontMetricsInt fm = mPaint.getFontMetricsInt();
mCoordinateY = getHeight() / 2 - fm.descent + (fm.descent - fm.ascent) / 2;
//绘制文本
canvas.drawText(mText, mCoordinateX, mCoordinateY, mPaint);
//如果不能滚动 则停止绘制
if (!isScroll) {
return;
}
//每绘制一次 X轴的偏移量 减去滚动速度 再进行绘制
mCoordinateX -= mSpeed;
if (mScrollType == SCROLL_ENDED) {
//当文本向左偏移text的宽度后 即所有文字都从屏幕左侧出去后 重置X轴的偏移量 让文字重新由右边进入
if (Math.abs(mCoordinateX) > mTextWidth && mCoordinateX < 0) {
mCoordinateX = mViewWidth;//重置X轴偏移量为控件宽度
}
} else {
//当文本剩余内容快要结束(快要离开屏幕mFollowSpace距离)时,开始绘制新一轮的文字
if ((Math.abs(mCoordinateX) + mFollowSpace) > mTextWidth && mCoordinateX < 0 && mCoordinateX_ > -4) {
canvas.drawText(mText, mCoordinateX_, mCoordinateY, mPaint);
mCoordinateX_ -= mSpeed;
}
}
invalidate();
}
}