android 自定义 view format,Android 自定义View金额、价格样式显示MoneyView

本文介绍了一位开发者如何根据设计需求创建自定义的MoneyView组件。通过在XML布局中添加依赖并设置属性,实现了金额文本的定制,包括元、分的字体大小,前缀文本、颜色和大小,以及小数点和前缀的间距等。开发者详细解释了从定义属性到获取属性值,再到测量和绘制的过程,展示了自定义View的完整流程。
摘要由CSDN通过智能技术生成

效果图:

035110d035a4

layout-2016-09-01-182947.png

使用方式

在 app的build.gradle 添加依赖

compile 'com.github.cchao:moneyview:1.0.1'

在 XML布局文件 中引用

android:layout_width="wrap_content"

android:layout_height="wrap_content"

money:money_text="789456.123"/>

显示效果就是效果图的第一个。

balabala

故事是这样的:

不懂设计从哪里搞得效果图,要求实现金额文本里元的字体较大,分的字体较小,而且前面的前缀样式还不定。各个页面的样式还不一致,为了满足妹子特别的需求。

就哒哒哒码了个MoneyView。

思路

根据妹子已给出的图,我猜,没错,我是猜的。鬼懂她什么时候想想又乱改了。so,从以下几个方面去规定这个MoneyView应该具备怎么样的样式:

元和分能自定义大小

前缀能自定义文本、颜色和大小

前缀与文本能自定义padding

小数点能自定义左右间隔

金额能自定义颜色

允许设置千分符

attrs

其实还可能有更多的,不过她如果这么过分的话,我就继承ViewGroup的子类了,哼。

好了,根据上述规定,程序员写出了下列attr:

constructor

没错,各位看官也可以有这样的思路去自定义View,先想好可能的拓展,再列出attr,最后才开始写代码。

好,既然我们写完了attr,就开始去学代码了。先new 一个Class 名字叫做MoneyView,然后复写其三个构造方法:

public MoneyView(Context context) {

this(context, null);

}

public MoneyView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public MoneyView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(context, attrs, defStyle);

}

private void init(Context context, AttributeSet attrs, int defStyle) {

TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MoneyView, defStyle, 0);

mMoneyText = typedArray.getString(R.styleable.MoneyView_money_text);

mMoneyColor = typedArray.getColor(R.styleable.MoneyView_money_color, mMoneyColor);

mYuanSize = typedArray.getDimensionPixelSize(R.styleable.MoneyView_yuan_size, mYuanSize);

mCentSize = typedArray.getDimensionPixelSize(R.styleable.MoneyView_cent_size, mCentSize);

mPrefix = typedArray.getString(R.styleable.MoneyView_prefix_text);

mPrefixSize = typedArray.getDimensionPixelSize(R.styleable.MoneyView_prefix_size, mPrefixSize);

mPrefixColor = typedArray.getColor(R.styleable.MoneyView_prefix_color, mPrefixColor);

mPrefixPadding = typedArray.getDimensionPixelSize(R.styleable.MoneyView_prefix_padding, mPrefixPadding);

mPointPaddingLeft = typedArray.getDimensionPixelSize(R.styleable.MoneyView_point_padding_left, mPointPaddingLeft);

mPointPaddingRight = typedArray.getDimensionPixelSize(R.styleable.MoneyView_point_padding_right, mPointPaddingRight);

mIsGroupingUsed = typedArray.getBoolean(R.styleable.MoneyView_grouping, false);

typedArray.recycle();

// 获得绘制文本的宽和高

mPaint = new Paint();

mPaint.setAntiAlias(true); // 消除锯齿

mPaint.setFlags(Paint.ANTI_ALIAS_FLAG); // 消除锯齿

mYuanBound = new Rect();

mCentBound = new Rect();

mPointBound = new Rect();

mPrefixBound = new Rect();

if (TextUtils.isEmpty(mPrefix)) {

mPrefix = "¥";

}

}

通过TypedArray 获取我们刚才写的attr

public int getDimensionPixelSize(int index, int defValue) {

用户不输入我们就给予默认值。默认在声明成员属性处已经给出。

onMeasure

那,现在我们也获取到用户设置的属性了,现在就要调用onMeasure去计算这个自定义MoneyView占据的宽高了。(代码有删减)

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width;

int height;

int pointPosition = mMoneyText.indexOf(POINT);

if (!mMoneyText.contains(POINT)) {

pointPosition = mMoneyText.length();

}

//获取元的文本

mYuan = mMoneyText.substring(0, pointPosition);

//如果使用千分符

if (mIsGroupingUsed) {

mYuan = NumberFormat.getInstance().format(Long.valueOf(mYuan));

}

//获取分的文本

mCent = mMoneyText.substring(pointPosition + 1, mMoneyText.length());

//获取元小数点、的占据宽高

mPaint.setTextSize(mYuanSize);

mPaint.getTextBounds(mYuan, 0, mYuan.length(), mYuanBound);

mPaint.getTextBounds(POINT, 0, POINT.length(), mPointBound);

//获取分占据宽高

mPaint.setTextSize(mCentSize);

mPaint.getTextBounds(mCent, 0, mCent.length(), mCentBound);

//获取前缀占据宽高

mPaint.setTextSize(mPrefixSize);

mPaint.getTextBounds(mPrefix, 0, mPrefix.length(), mPrefixBound);

//文本占据的宽度

mTextWidth = mYuanBound.width() + mCentBound.width() + mPrefixBound.width() + mPointBound.width()

+ mPointPaddingLeft + mPointPaddingRight + mPrefixPadding;

// 设置宽度

int specMode = MeasureSpec.getMode(widthMeasureSpec);

int specSize = MeasureSpec.getSize(widthMeasureSpec);

if (specMode == MeasureSpec.EXACTLY) {

width = specSize + getPaddingLeft() + getPaddingRight();

} else {

width = mTextWidth + getPaddingLeft() + getPaddingRight();

}

// 设置高度

// 获取最大字号

int maxSize = Math.max(mYuanSize, mCentSize);

maxSize = Math.max(maxSize, mPrefixSize);

mPaint.setTextSize(maxSize);

// 获取基线距离

maxDescent = mPaint.getFontMetrics().descent;

int maxHeight = Math.max(mYuanBound.height(), mCentBound.height());

maxHeight = Math.max(maxHeight, mPrefixBound.height());

// 文本占据的高度 (给顶线和底线留间距)

mTextHeight = maxHeight + (int) (maxDescent * 2 + 0.5f);

specMode = MeasureSpec.getMode(heightMeasureSpec);

specSize = MeasureSpec.getSize(heightMeasureSpec);

if (specMode == MeasureSpec.EXACTLY) {

height = specSize;

} else {

height = mTextHeight;

}

setMeasuredDimension(width, height);

}

我们分别计算前缀,元,分占据的宽高,然后对比,取最高的一个作为MoneyView的高。

这里获取了最大文本的基线值maxDescent。这里需要注意一点,canvas.drawText是根据 baseLine(基线) 绘制的,这和我们小时候用四线纸去写字母一个意思,如下图:

035110d035a4

e038aae657b1832ecc32c336c6075ffc.jpg

onDraw

所以我们在 onDraw()时要在Y轴上加上基线距离底部的值,才是我们需要绘制的, 绘制过程会将文本居中。

@Override

protected void onDraw(Canvas canvas) {

//绘制X坐标

int drawX = (getMeasuredWidth() - mTextWidth) / 2;

float drawY = (getMeasuredHeight() + mTextHeight) / 2 - maxDescent;

//绘制前缀

mPaint.setColor(mPrefixColor);

mPaint.setTextSize(mPrefixSize);

canvas.drawText(mPrefix, drawX, drawY, mPaint);

//绘制元

drawX += mPrefixBound.width() + mPrefixPadding;

mPaint.setColor(mMoneyColor);

mPaint.setTextSize(mYuanSize);

canvas.drawText(mYuan, drawX, drawY, mPaint);

//绘制小数点

drawX += mYuanBound.width() + mPointPaddingLeft;

canvas.drawText(POINT, drawX, drawY, mPaint);

//绘制分

drawX += mPointPaddingRight;

mPaint.setTextSize(mCentSize);

canvas.drawText(mCent, drawX, drawY, mPaint);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值