您的位置:首页 > 移动开发 > Android开发

android 自定义控件(二)

2016-06-15 19:45 399 查看
转自:鸿洋博客,正在学习,非常感谢!

之前已经初步了解了自定义,现在要做的是自定义View显示一张图片,下面包含图片的文本介绍。

1.自定义基本属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>

<attr name="textSize" format="dimension" />
<attr name="textTitle" format="string" />
<attr name="textColor" format="color" />
<attr name="img" format="reference" />
<attr name="imgScaleType">
<enum name="fillXY" value="0" />
<enum name="center" value="1" />
</attr>

<declare-styleable name="CustomeView2">
<attr name="textSize" />
<attr name="textTitle" />
<attr name="textColor" />
<attr name="img" />
<attr name="imgScaleType" />

</declare-styleable>
</resources>


2.自定义控件CustomeView:

Paint mPaintText, mPaintDraw;

Rect textRect, imgRect;
//定义一些基本属性
private String mTextTitle;
private int mTextSize;
private int mTextColor;
private Bitmap img;
private int mImgScaleType;

//最终要显示的高和宽
private int width;
private int height;

public CustomeView2(Context context) {
this(context, null);
}

public CustomeView2(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public CustomeView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomeView2, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CustomeView2_textTitle:
mTextTitle = a.getString(R.styleable.CustomeView2_textTitle);
break;
case R.styleable.CustomeView2_textColor:
mTextColor = a.getColor(attr, Color.BLACK);//默认黑色字体
break;
case R.styleable.CustomeView2_textSize://这里用的是px
mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));//默认16sp
break;
case R.styleable.CustomeView2_img:
img = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
break;
case R.styleable.CustomeView2_imgScaleType:
mImgScaleType = a.getInt(attr, 0);
break;
}
}

a.recycle();

mPaintDraw = new Paint();
mPaintText = new Paint();
textRect = new Rect();
imgRect = new Rect();
mPaintText.setTextSize(mTextSize);
mPaintText.getTextBounds(mTextTitle, 0, mTextTitle.length(), textRect);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//绘制边框
mPaintDraw.setStrokeWidth(1);//这个边框大小暂写死
mPaintDraw.setAntiAlias(true);//消除锯齿
mPaintDraw.setStyle(Paint.Style.STROKE);//空心
mPaintDraw.setColor(mTextColor);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaintDraw);

//此时绘制的text过于长让其显示”哈哈哈哈....“
mPaintText.setColor(mTextColor);
if (textRect.width() > width) {

TextPaint paint = new TextPaint(mPaintText);

String msg = TextUtils.ellipsize(mTextTitle, paint, width - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END).toString();

//绘制textView 放在图片的上面
//绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
canvas.drawText(msg, getPaddingLeft(), getPaddingTop() + textRect.height(), paint);

//绘制textView  放在图片的下面
//绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
canvas.drawText(msg, getPaddingLeft(), height - getPaddingBottom(), paint);

} else {
//绘制textView 放在图片的上面
//绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
canvas.drawText(mTextTitle, getWidth() / 2 - textRect.width() / 2 - getPaddingLeft() + getPaddingRight(), getPaddingTop() + textRect.height(), mPaintText);

//绘制textView  放在图片的下面
//绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
canvas.drawText(mTextTitle, getWidth() / 2 - textRect.width() / 2 - getPaddingLeft() + getPaddingRight(), height - getPaddingBottom(), mPaintText);
}

//绘制图片的绘制区域。放在textView的下面
imgRect.left = getPaddingLeft();
imgRect.right = width - getPaddingRight();
imgRect.bottom = height - getPaddingBottom() - textRect.height();
//这个地方由于还要绘制一个textVIew 所以他的高度应该要改变
imgRect.top = getPaddingTop() + textRect.height();//绘制图在textView
canvas.drawBitmap(img, null, imgRect, mPaintDraw);

}


现在的效果:




然后之前设置width 为warp_content的时候会出现平铺的效果,这个时候我们需要重写OnMeasure()方法:

int specModeWidth = MeasureSpec.getMode(widthMeasureSpec);
int specSizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int specModeHeight = MeasureSpec.getMode(heightMeasureSpec);
int specSizeHeight = MeasureSpec.getSize(heightMeasureSpec);
if (specModeWidth == MeasureSpec.EXACTLY) {//match
width = specSizeWidth;
} else {
//这个时候要判断是图片太长还是文字太长
int imgWidth = getPaddingLeft() + img.getWidth() + getPaddingRight();
int textWidth = getPaddingLeft() + textRect.width() + getPaddingRight();

//在其设置为wrap_content的时候
if (specModeWidth == MeasureSpec.AT_MOST) {//会由子控件的宽度觉得
int desireWidth = Math.max(imgWidth, textWidth);

//这个时候,子控件设置的宽wrap_content,最终的宽会由父控件和自控件的宽的稍小值决定
width = Math.min(desireWidth, specSizeWidth);
}

}

if (specModeHeight == MeasureSpec.EXACTLY) {
height = specSizeHeight;
} else {
int desireHeight = getPaddingBottom() + img.getHeight() + getPaddingTop() + textRect.height();
if (specModeHeight == MeasureSpec.AT_MOST) {
height = Math.min(desireHeight, specSizeHeight);
}

}
setMeasuredDimension(width, height);
Log.i("yqy", getMeasuredHeight() + "," + getMeasuredWidth());


这个时候的效果是:



然后我们发现之前定义的imgStyleType我们并没有使用,这个又是做什么的呢?这个是用来区分绘制的图片是否是平铺还是中心显示,这个我们在OnDraw方法里面实现:

if (mImgScaleType == 0) {//平铺

canvas.drawBitmap(img, null, imgRect, mPaintDraw);
} else {//中心显示
imgRect.left = width / 2 - imgRect.width() / 2;
imgRect.right = width / 2 + imgRect.width() / 2;
imgRect.top = height / 2 + (textRect.height() / 2) * 2 - imgRect.height() / 2;
imgRect.bottom = height / 2 - (textRect.height() / 2) * 2 + imgRect.height() / 2;

canvas.drawBitmap(img, null, imgRect, mPaintDraw);
}


效果图:


于上面一张图对比有没有发现图片的显示不一样?这就是imgStyleType的效果。

笔记总结:

1.代码编写的时候加上一个textView 让自己熟悉一下计算什么的

2.中间出现一个错误:

Caused by: android.content.res.Resources$NotFoundException: File #009933 from drawable resource ID #0x0: .xml extension required


原因是属性styleable.xml中

<attr name="textColor" format="color" />


color属性我写成了string

3. ondraw中不要new 对象,耗内存这个要修改优化。

以上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: