前面已经简单介绍过一些自定义View的实现,现在再利用自定义View实现显示一张图片的功能
1、首先编写attrs.xml文件
<resources>
<declare-styleable name="CustomImageView">
<attr name="text" format="string" />
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
<attr name="background" format="reference" />
<attr name="imageScaleType">
<enum name="fillXY" value="0" />
<enum name="center" value="1" />
</attr>
</declare-styleable>
</resources>
2、在自定义View中获得我们自定义属性:
public class CustomImageView extends View {
/**
* 自定义View的宽
*/
private int mWidth;
/**
* 自定义View的高
*/
private int mHeight;
/**
* 自定义View的图片
*/
private Bitmap mImage;
/**
* 图片的缩放模式
*/
private int mImageScale;
private static final int IMAGE_SCALE_FITXY = 0;
private static final int IMAGE_SCALE_CENTER = 1;
/**
* 图片的标题
*/
private String mTitle;
/**
* 字体的颜色
*/
private int mTextColor;
/**
* 字体的大小
*/
private int mTextSize;
private Paint mPaint;
/**
* 文本的绘制范围
*/
private Rect mTextBound;
/**
* 需要绘制的整个矩形范围
*/
private Rect rect;
public CustomImageView(Context context) {
this(context, null);
}
public CustomImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* 初始化自定义类型
*
* @param context
* @param attrs
* @param defStyle
*/
public CustomImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(
attrs, R.styleable.CustomImageView, defStyle, 0);
mTitle = typedArray.getString(typedArray.getIndex(0));//获得自定义属性的title
//获得自定义属性的textSize
mTextSize = typedArray.getDimensionPixelSize(typedArray.getIndex(1),
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16,
getResources().getDisplayMetrics()));
//获得自定义属性的textColor
mTextColor = typedArray.getColor(typedArray.getIndex(2), Color.BLACK);
//获得自定义属性的image
mImage = BitmapFactory.decodeResource(getResources(),
typedArray.getResourceId(typedArray.getIndex(3), 0));
//自定义属性的imageScale
mImageScale = typedArray.getInt(typedArray.getIndex(4), 0);
typedArray.recycle();
rect = new Rect();
mPaint = new Paint();
mTextBound = new Rect();
mPaint.setTextSize(mTextSize);
// 计算描绘字体需要的范围
mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound);
}
3、重写onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 设置自定义View的宽度
*/
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
{
mWidth = specSize;
} else {
// 自定义View的宽度,由左右填充和图片宽度决定
int desireByImg = getPaddingLeft() + getPaddingRight()
+ mImage.getWidth();
// 由左右填充和字体绘制范围的宽度决定
int desireByTitle = getPaddingLeft() + getPaddingRight()
+ mTextBound.width();
if (specMode == MeasureSpec.AT_MOST)// wrap_content
{
int desire = Math.max(desireByImg, desireByTitle);
mWidth = Math.min(desire, specSize);
}
}
/***
* 设置自定义View
*/
specMode = MeasureSpec.getMode(heightMeasureSpec);
specSize = MeasureSpec.getSize(heightMeasureSpec);
if (specMode == MeasureSpec.EXACTLY)// 设置了明确的值或者是MATCH_PARENT
{
mHeight = specSize;
} else {
//由上下填充、图片的高度和字体绘制范围的高度决定
int desire = getPaddingTop() + getPaddingBottom()
+ mImage.getHeight() + mTextBound.height();
if (specMode == MeasureSpec.AT_MOST)// wrap_content
{
mHeight = Math.min(desire, specSize);
}
}
//为控件指定大小
setMeasuredDimension(mWidth, mHeight);
}
4、重写onDraw
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 边框属性
*/
mPaint.setStrokeWidth(4);// 设置画笔宽度
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.CYAN);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
rect.left = getPaddingLeft();
rect.right = mWidth - getPaddingRight();
rect.top = getPaddingTop();
rect.bottom = mHeight - getPaddingBottom();
mPaint.setColor(mTextColor);
mPaint.setStyle(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_FITXY) {
//绘制image
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);
}
}
做完这些,我们就可以在activity_main.xml文件中引用了
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.example.activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.activity.view.CustomImageView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
custom:background="@drawable/ic_launcher"
custom:imageScaleType="center"
custom:text="hello world !"
custom:textColor="#00ff00"
custom:textSize="20sp" />
<com.example.activity.view.CustomImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
custom:background="@drawable/ic_launcher"
custom:imageScaleType="center"
custom:text="hello world ! "
custom:textColor="#ff0000"
custom:textSize="30sp" />
<com.example.activity.view.CustomImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:padding="10dp"
custom:background="@drawable/wheat"
custom:imageScaleType="fillXY"
custom:text="麦子"
custom:textColor="#ff0000"
custom:textSize="12sp" />
</LinearLayout>
一共有三种效果:
- View宽度设置为精确值,字体的长度大于此宽度
- View宽度设置为wrap_content,字体的宽度大于图片
- View宽度设置为wrap_content, 字体的宽度小于图片