继承自View的文本+图像显示控件CustomViewImage,需要自定义属性:文字内容,字体颜色和字体大小;图像资源和图像显示方式。
第一步:资源文件中定义属性
<attr name="titleText" format="string" />
<attr name="titleTextColor" format="color" />
<attr name="titleTextSize" format="dimension" />
<attr name="image" format="reference" />
<attr name="imageScaleType">
<enum name="fillXY" value="0" />
<enum name="center" value="1" />
</attr>
<declare-styleable name="CustomViewImage">
<attr name="titleText" />
<attr name="titleTextSize" />
<attr name="titleTextColor" />
<attr name="image" />
<attr name="imageScaleType" />
</declare-styleable>
第二步:在布局文件中添加 CustomViewImag e,注意定义xmlns:custom,可以更改的是属性资源所在的包名[com.twelve],即manifest文件中定义的包名。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.twelve"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.twelve.custom.CustomViewImage
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp"
custom:image="@drawable/girl"
custom:imageScaleType="fillXY"
custom:titleText="妹子~"
custom:titleTextColor="#ff0000"
custom:titleTextSize="12sp"/>
</LinearLayout>
第三步,获取自定义属性值
public CustomViewImage(Context context) {
this(context, null);
}
public CustomViewImage(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomViewImage(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
/**
* 初始化控件边界
*/
rect = new Rect();
/**
* 初始化画笔对象
*/
mPaint = new Paint();
/**
* 初始化文本绘制框
*/
mTextBound = new Rect();
/**
* 获取文本和图像属性
*/
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomViewImage, defStyle, 0);
int n = a.length();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CustomViewImage_image:
/**
* 获取图像对象
*/
mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
break;
case R.styleable.CustomViewImage_imageScaleType:
/**
* 获取图像显示模式
*/
mImageScale = a.getInt(attr, 0);
break;
case R.styleable.CustomViewImage_titleText:
/**
* 获取文本内容
*/
mTitle = a.getString(attr);
break;
case R.styleable.CustomViewImage_titleTextColor:
/**
* 获取文本颜色
*/
mTextColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomViewImage_titleTextSize:
/**
* 获取文本字号
*/
mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
16, getResources().getDisplayMetrics()));
mPaint.setTextSize(mTextSize);
break;
}
}
a.recycle();
/**
* 获取文本占据上控件画布的大小
*/
mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound);
}
第四步:确定控件的宽度和高度
/**
* 确定视图的总宽度和总高度
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
/**
* 设置宽度
*/
if (widthMode == MeasureSpec.EXACTLY){
/**
* 如果显示模式为指定大小,宽度就是给定的宽度
*/
mWidth = widthSize;
} else {
/**
* 由图片决定的宽度:图片本身的宽度+与边界的距离
*/
int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth();
/**
* 由文字决定的宽度:文字本身的宽度+与边界的距离
*/
int desireByTitle = getPaddingLeft() + getPaddingRight() + mTextBound.width();
/**
* 可变宽度下,原则上使得内容显示不超出边界。
*/
int desire = Math.max(desireByImg, desireByTitle);
mWidth = Math.min(desire, widthSize);
}
/**
* 设置高度
*/
if (heightMode == MeasureSpec.EXACTLY){
/**
* 如果显示模式为指定大小,高度就是给定的高度
*/
mHeight = heightSize;
} else {
/**
* 由图片和文字决定的高度:图片本身的高度+文字本身高度+与边界的距离
*/
int desire = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height();
/**
* 可变高度下,原则上使得内容显示不超出边界。
*/
mHeight = Math.min(desire, heightSize);
}
setMeasuredDimension(mWidth, mHeight);
}
第五步,按照上面图像下面文字的方式,把文字和图像显示显示到屏幕上。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStrokeWidth(4);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLUE);
/**
* 边框:View视图最外边框,与内容距离--padding
*/
canvas.drawRect(0,0,getWidth(),getHeight(), mPaint);
rect.left = getPaddingLeft();
rect.right = mWidth - getPaddingRight();
rect.top = getPaddingTop();
rect.bottom = mHeight - getPaddingBottom();
/**
* 边框:紧贴着文字和图像内容的长方形边框
*/
mPaint.setColor(Color.RED);
canvas.drawRect(rect, mPaint);
mPaint.setColor(mTextColor);
mPaint.setStyle(Paint.Style.FILL);
/**
* 当前设置的宽度小于字体需要的宽度,将字体改为xxx...
*/
if (mTextBound.width() > mWidth) {
TextPaint paint = new TextPaint(mPaint);
String msg = TextUtils.ellipsize(mTitle, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(),
TextUtils.TruncateAt.END).toString();
canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint);
} else {
/**
* 正常情况,将字体居中
*/
canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2, mHeight - getPaddingBottom(), mPaint);
}
/**
* 图形显示在文字的上方,图形可使用的位置高度要减去文字已经使用的高度。
*/
rect.bottom -= mTextBound.height();
/**
* 如果图片显示模式为填充模式,图片沾满余下的空间
*/
if (mImageScale == IMAGE_SCALE_FIT_XY) {
canvas.drawBitmap(mImage, null, rect, mPaint);
} else {
/**
* 如果不沾满,图形居中显示,有可能图像不能完全显示在给定的范围内
*/
rect.left = mWidth / 2 - mImage.getWidth() / 2;
rect.right = mWidth / 2 + mImage.getWidth() / 2;
rect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight() / 2;
rect.bottom = (mHeight - mTextBound.height()) / 2 + mImage.getHeight() / 2;
canvas.drawBitmap(mImage, null, rect, mPaint);
}
}
canvas画方框时传入的是方框对象;canvas画图片时,传入方框是图像的边界,图像会被画在方框内;canvas画文字时,传入的是文字左下角的点坐标。