步骤
- 自定义属性
- 重写onMeasure(…)
- 重写onDraw(…)
带着问题看代码
- 怎么获取图片资源
- 怎么确定View的位置
- 在字符串过长时,怎么在后面加入省略号
- 在什么时候调用onDraw(…)和onMeasure()方法 (以后分析)
效果图
- 第一个View的width_parent和height_parent固定为180dp
- 第二个View的width_parent和height_parent为wrap_content
- 第三个View的width_parent和height_parent为match_parent
布局文件
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:test="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical"
tools:context="com.nobita.customimageview.MainActivity">
<com.nobita.customimageview.MyImageView
android:layout_width="180dp"
android:layout_height="180dp"
test:mImage="@mipmap/ic_launcher"
test:mImageSize="30dp"
test:mText="Hello Worldfffffffffffffffffff!"
test:mTextColor="#f00"
test:mTextSize="20sp"/>
<com.nobita.customimageview.MyImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
test:mImage="@mipmap/ic_launcher"
test:mImageSize="30dp"
test:mText="Hello World!"
test:mTextColor="#f00"
test:mTextSize="20sp"/>
<com.nobita.customimageview.MyImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
test:mImage="@mipmap/ic_launcher"
test:mImageSize="30dp"
test:mText="Hello Worldfffffffffffffffffff!"
test:mTextColor="#f00"
test:mTextSize="20sp"/>
</LinearLayout>
attrs.xml
<resources>
<declare-styleable name="MyImageView">
<attr name="mImage" format="reference"></attr>
<attr name="mImageSize" format="dimension"></attr>
<attr name="mText" format="string"></attr>
<attr name="mTextSize" format="dimension"></attr>
<attr name="mTextColor" format="color"></attr>
</declare-styleable>
</resources>
自定义View代码
public class MyImageView extends View {
private String mText;
private int mTextColor;
private float mTextSize;
private float mImageSize;
private int mImageSrc;
private Paint mPaint;
private final Bitmap mBitmap;
private int mTextWidthSize;
private int mTextHeightSize;
private int mImageWidthSize;
private int mImageHeightSize;
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyImageView);
mText = a.getString(R.styleable.MyImageView_mText);
mTextSize = a.getDimension(R.styleable.MyImageView_mTextSize, 30);
mTextColor = a.getColor(R.styleable.MyImageView_mTextColor, Color.GREEN);
mImageSize = a.getDimension(R.styleable.MyImageView_mImageSize, 30);
mBitmap = BitmapFactory.decodeResource(getResources(), a.getResourceId(R.styleable.MyImageView_mImage, 0));
a.recycle();
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width;
int height;
Rect mBound = new Rect();
mPaint.getTextBounds(mText, 0, mText.length(), mBound);
mTextWidthSize = mBound.width();
mTextHeightSize = mBound.height();
mImageWidthSize = mBitmap.getWidth();
mImageHeightSize = mBitmap.getHeight();
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = mTextWidthSize > mImageWidthSize ? mTextWidthSize : mImageWidthSize + getPaddingLeft() + getPaddingRight();
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = mTextHeightSize + mImageHeightSize + getPaddingBottom() + getPaddingTop();
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
Paint mBorderPaint = new Paint();
mBorderPaint.setStrokeWidth(4);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setColor(Color.GREEN);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mBorderPaint);
int mTextX = getMeasuredWidth() / 2 - mTextWidthSize / 2;
int mTextY = getMeasuredHeight() / 2 + mTextHeightSize / 2 + mImageHeightSize / 2;
int mImageX = getMeasuredWidth() / 2 - mImageWidthSize / 2;
int mImageY = getMeasuredHeight() / 2 - mImageHeightSize / 2 - mTextHeightSize / 2;
Rect bound = new Rect();
int length = 0;
if (mTextWidthSize > getMeasuredWidth()) {
for (int i = 0; i < mText.length(); i++) {
mPaint.getTextBounds(mText + "...", 0, i + 3, bound);
if (bound.width() >= getMeasuredWidth()) {
length = i > 0 ? --i : 0;
break;
}
}
mText = mText.substring(0, length) + "...";
mTextX = 0;
}
canvas.drawText(mText, mTextX, mTextY, mPaint);
canvas.drawBitmap(mBitmap, mImageX, mImageY, new Paint());
}
}
构造函数
onMeasure(…)
- 通过字符串和图片的长宽,根据Mode的样式来确定View长宽,最后setMeasuredDimension(width, height);
onDraw(…)
- 计算字符串和图片应该放置的位置
- 计算字符串是否需要结尾省略号