跳动的数字和金额、滑动的数字
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import com.shoneworn.supermvp.uitls.NumberUtils; /** * Created by chenxiangxiang on 2019/5/16. * * @author shoneworn * @只支持单个文字的跳动,只想支持数字。 */ public class SingleScrollNumberView extends View { private String mText = ""; private int mTextColor = Color.BLACK; private int mTextSize = 48; private int textPadding = 6; private Paint mPaint; private Context mContext; private static String BASE_NUMBER = "0123456789"; /** * 由于只想用一个view完事,但是文字绘制的时候,不带边距,只好在measure的时候,用大字体占个大位置。在onDraw的时候,用小字体。这样文字就自带了边距 */ private int textOutHeight; private int textOutWidth; private int textInnerWidth; private int scrollY = 0; private int scale = 2; public SingleScrollNumberView(Context context) { this(context, null); } public SingleScrollNumberView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public SingleScrollNumberView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; initPaint(); } private void initPaint() { mPaint = new Paint(); //设置抗锯齿 mPaint.setAntiAlias(true); //设置字体和颜色 mPaint.setTextSize(mTextSize * scale); mPaint.setColor(mTextColor); setPadding(textPadding, textPadding, textPadding, textPadding); } public SingleScrollNumberView setText(String text) { this.mText = text; return this; } public SingleScrollNumberView setTextColor(int textColor) { this.mTextColor = textColor; mPaint.setColor(mTextColor); return this; } public SingleScrollNumberView setTextSize(int textSize) { this.mTextSize = textSize; mPaint.setTextSize(mTextSize * scale); return this; } public SingleScrollNumberView setTextPadding(int padding) { this.textPadding = padding; setPadding(textPadding, textPadding, textPadding, textPadding); return this; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.AT_MOST) { Rect bounds = new Rect(); mPaint.getTextBounds(mText, 0, mText.length(), bounds); textOutWidth = bounds.width(); width = bounds.width() + getPaddingLeft() + getPaddingRight(); } if (heightMode == MeasureSpec.AT_MOST) { Rect bounds = new Rect(); mPaint.getTextBounds(mText, 0, mText.length(), bounds); textOutHeight = bounds.height(); height = textOutHeight + getPaddingTop() + getPaddingBottom(); } //设置宽高 setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (TextUtils.isEmpty(mText)) return; if (mText.length() > 1) return; if (!BASE_NUMBER.contains(mText)) return; //保持垂直方向居中 //getPaddingLeft() + (textOutWidth - textInnerWidth) / 2 保持水平方向居中 mPaint.setTextSize(mTextSize); Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom; int baseLine = getHeight() / 2 + dy; for (int i = 0; i <= NumberUtils.toInt(mText); i++) { mPaint.setTextSize(mTextSize); Rect innerBounds = new Rect(); mPaint.getTextBounds(mText, 0, mText.length(), innerBounds); textInnerWidth = innerBounds.width(); canvas.drawText(String.valueOf(i), getPaddingLeft() + (textOutWidth - textInnerWidth) / 2, baseLine + i * textOutHeight - scrollY, mPaint); } } private void animateView() { this.postDelayed(new Runnable() { @Override public void run() { //最大数字出现后,就要停下来。还要停稳,不然多几个数字,就会出现高低不平了。 if (scrollY >= textOutHeight * NumberUtils.toInt(mText)) { scrollY = textOutHeight * NumberUtils.toInt(mText); SingleScrollNumberView.this.postInvalidate(); return; } scrollY += textOutHeight / 4; SingleScrollNumberView.this.postInvalidate(); animateView(); } }, 8); } public void start() { scrollY = 0; animateView(); } }
public class DanceNumberView extends LinearLayout { private String text; private int textColor; private int textSize; private float textPadding; //文字间距 private List<SingleScrollNumberView> list = new ArrayList<>(); public DanceNumberView(Context context) { this(context, null); } public DanceNumberView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public DanceNumberView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.scrollNumber); initAttributesData(typedArray); this.setOrientation(HORIZONTAL); this.setGravity(Gravity.CENTER); } public void createView() { if (TextUtils.isEmpty(text)) return; char[] chars = String.valueOf(NumberUtils.toInt(text)).toCharArray(); for (int i = 0; i < chars.length; i++) { SingleScrollNumberView scrollNumber = new SingleScrollNumberView(getContext()); scrollNumber.setTextColor(textColor); scrollNumber.setTextSize(textSize); scrollNumber.setText(String.valueOf(chars[i])); addView(scrollNumber); list.add(scrollNumber); } } public void start() { if (Utils.isEmpty(list)) return; for (SingleScrollNumberView view : list) { view.start(); } } private void initAttributesData(TypedArray typedArray) { textColor = typedArray.getColor(R.styleable.scrollNumber_textColor, Color.BLACK); textSize = (int) typedArray.getDimension(R.styleable.scrollNumber_textSize, 16); text = typedArray.getString(R.styleable.scrollNumber_text); textPadding = typedArray.getDimension(R.styleable.scrollNumber_textPadding, 5); } }
新建资源scroll_number_attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="scrollNumber"> <attr name="text" format="string" /> <attr name="textSize" format="dimension" /> <attr name="textColor" format="color" /> <attr name="textPadding" format="dimension" /> </declare-styleable> </resources>
使用
<com.shoneworn.supermvp.common.widget.DanceNumberView android:id="@+id/dnView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#666666" app:text="33891856" app:textColor="#ffffff" app:textPadding="2dp" app:textSize="16sp" />
dnView.createView();
dnView.start();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通