这是个什么控件呢?
有这第一些要求,平时我们在UI上显示时间,通常直接是显示:11:45这样格式的文字
如果要求这些数字和符号用图片替换呢?
通常来产,大家可能想到的是用ImageView来显示单独的图片,根据时间数字去获取对应的图片。
对于这种特定长度,并且不太长的是可以的。如果这个数字是2938424542323.32呢?对吧,你总不能写N个ImageView吧,当然可以优化一下,代码动态把ImageView添加到容器中。
如何实现呢?
可以自己写个控件,不会自定义控件编写步骤的同学,可以参考一下Android自定义控件基础课程
基本的架子
public class NumberImageView extends View {
public NumberImageView(Context context) {
this(context, null);
}
public NumberImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NumberImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
构造方法,刚学android的同学可能会问,为什么要三个构造函数,并且都调用到第三个去。
提供三个构造方法是为了满足多种不同的创建方式,都调用到第三个是为了统一入口,我们把初始化的相关代码写在第三个构造方法即可。其他构造方法进来也会走到那里的。
数据设置
我们可以暴露一个方法,跟TextView一样,设置文字内容。
这里成,我们涉及到把字符串打散成字符,然后把字符转成图片。
public void setText(String text) {
char[] chars = text.toCharArray();
resArray = new Bitmap[chars.length];
try {
for (int i = 0; i < chars.length; i++) {
char aChar = chars[i];
int mipmap = getResources().getIdentifier("number_" + (int) aChar, "mipmap", getContext().getPackageName());
if (mipmap == 0) {
throw new IllegalArgumentException("no resource name: number_" + (int) aChar + " in mipmap folder.");
}
resArray[i] = BitmapFactory.decodeResource(getResources(), mipmap, options);
}
//长度变化以后,需要重新测量
if (lastLen != text.length()) {
requestLayout();
lastLen = text.length();
}
invalidate();
} catch (Exception e) {
e.printStackTrace();
}
}
可以看到,我这里的图片命名是根据ASSIC的十进制码进行映射的,这样子我直接把字符转成图片。
昨天有个同学提了个问题:
以上方式就可获取到。
测量
按我们自定义控件的步骤,我们测量一下自己,这是一个自定义View。
本控件的宽度,只要把所有孩子的宽度加起来即可,高度也是孩子的高度,因为这里的图片高度是一样的,所以我用一个就可以。如果图片高度不一样,可以获取到最高的那张图片,然后设置高度值。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (resArray == null) {
return;
}
Log.d(TAG, "on measure...");
//设置大小
int targetWidth = 0;
int targetHeight = 0;
for (Bitmap bitmap : resArray) {
targetWidth += bitmap.getWidth();
targetHeight = bitmap.getHeight();
}
setMeasuredDimension(targetWidth, targetHeight);
}
测量完了,有自己的空间了,在此控件进行绘制。
绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (resArray == null || resArray.length == 0) {
return;
}
Bitmap firstOne = resArray[0];
imgRect.left = 0;
imgRect.top = 0;
imgRect.bottom = firstOne.getHeight();
positionRect.left = 0;
positionRect.top = 0;
positionRect.right = firstOne.getWidth();
positionRect.bottom = firstOne.getHeight();
//计算位置
for (int i = 0; i < resArray.length; i++) {
Bitmap bitmap = resArray[i];
imgRect.right = bitmap.getWidth();
positionRect.right = positionRect.left + bitmap.getWidth();
canvas.drawBitmap(bitmap, imgRect, positionRect, paint);
positionRect.left += bitmap.getWidth();
}
}
绘制的代码也比较简单
拿着一张张图片从左往右绘制就完事了
我们这个只是展示类控件,不需要处理事件,展示内容就可以了。
完整代码
public class NumberImageView extends View {
private static final String TAG = "NumberImageView";
private Bitmap[] resArray;
private final Paint paint;
private final Rect imgRect;
private final Rect positionRect;
private final BitmapFactory.Options options;
public NumberImageView(Context context) {
this(context, null);
}
public NumberImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NumberImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//准备好画笔
paint = new Paint();
//准备好框框
imgRect = new Rect();
positionRect = new Rect();
options = new BitmapFactory.Options();
options.inScaled = false;
}
private int lastLen = 0;
public void setText(String text) {
char[] chars = text.toCharArray();
resArray = new Bitmap[chars.length];
try {
for (int i = 0; i < chars.length; i++) {
char aChar = chars[i];
int mipmap = getResources().getIdentifier("number_" + (int) aChar, "mipmap", getContext().getPackageName());
if (mipmap == 0) {
throw new IllegalArgumentException("no resource name: number_" + (int) aChar + " in mipmap folder.");
}
resArray[i] = BitmapFactory.decodeResource(getResources(), mipmap, options);
}
//长度变化以后,需要重新测量
if (lastLen != text.length()) {
requestLayout();
lastLen = text.length();
}
invalidate();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (resArray == null) {
return;
}
Log.d(TAG, "on measure...");
//设置大小
int targetWidth = 0;
int targetHeight = 0;
for (Bitmap bitmap : resArray) {
targetWidth += bitmap.getWidth();
targetHeight = bitmap.getHeight();
}
setMeasuredDimension(targetWidth, targetHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (resArray == null || resArray.length == 0) {
return;
}
Bitmap firstOne = resArray[0];
imgRect.left = 0;
imgRect.top = 0;
imgRect.bottom = firstOne.getHeight();
positionRect.left = 0;
positionRect.top = 0;
positionRect.right = firstOne.getWidth();
positionRect.bottom = firstOne.getHeight();
//计算位置
for (int i = 0; i < resArray.length; i++) {
Bitmap bitmap = resArray[i];
imgRect.right = bitmap.getWidth();
positionRect.right = positionRect.left + bitmap.getWidth();
canvas.drawBitmap(bitmap, imgRect, positionRect, paint);
positionRect.left += bitmap.getWidth();
}
}
}
``
# 使用控件
```xml
<com.sob.altitude.view.NumberImageView
android:layout_width="wrap_content"
android:id="@+id/number_text"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
设置数值:
numberImageView.setText("--.--");
其他数字
到这里,就水完这篇文章了,请有序打赏和点赞,鞠躬!