一,设置自定义控件所需属性,此设定可用于xml布局,在布局文件layout中设置绘制控件所需的color,paintwidth等。在res->values下的attrs文件加入所需属性:
<!--MyImageView属性定义-->
<attr name="borderRadius" format="dimension"></attr>
<attr name="imageType">
<enum name="circle" value="0"></enum>
<enum name="round" value="1"></enum>
</attr>
<declare-styleable name="MyImageView">
<attr name="borderRadius"></attr>
<attr name="imageType"></attr>
<attr name="weight" format="integer"></attr>
<attr name="hadFrame" format="boolean"></attr>
</declare-styleable>
declare-styleable中的name为layout中使用的控件name,attr中指定属性名及所属类型,layout文件使用如下:
<cn.cjwddz.knowu.view.MyImageView
android:id="@+id/myImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:src="@drawable/dfheader"
app:borderRadius="20dp"
app:imageType="circle"
app:weight="5"
>
</cn.cjwddz.knowu.view.MyImageView>
二,创建MyImageView的类,extends原生的Image View。实现init方法,初始化各类属性及获取自定义属性值
private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr){
//初始化各属性
matrix = new Matrix();
matrix1 = new Matrix();
paint = new Paint();
dPaint = new Paint();
framePaint = new Paint();
dPaint.setAntiAlias(true);
dPaint.setStyle(Paint.Style.FILL);
dPaint.setColor(Color.WHITE);
paint.setAntiAlias(true);
framePaint.setAntiAlias(true);
//获取自定义属性值
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyImageView,defStyleAttr,0);
int count = array.getIndexCount();
for(int i=0;i<count;i++){
int attr = array.getIndex(i);
switch (attr){
case R.styleable.MyImageView_borderRadius:
borderRadius = array.getDimensionPixelSize(R.styleable.MyImageView_borderRadius,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, BORDER_RADIUS_DEFAULT, getResources().getDisplayMetrics()));
break;
case R.styleable.MyImageView_imageType:
type = array.getInt(R.styleable.MyImageView_imageType,TYPE_CIRCLE);
break;
case R.styleable.MyImageView_weight:
weights = array.getInt(R.styleable.MyImageView_weight,WEIGHT);
break;
case R.styleable.MyImageView_hadFrame:
hadFrame = array.getBoolean(R.styleable.MyImageView_hadFrame,hadFrame);
default:break;
}
}
array.recycle();
}
通过下列代码获取attr数组
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyImageView,defStyleAttr,0);
并获取特定的属性值,第一个元素为attrs文件所对应id,第二个元素为默认值。
type = array.getInt(R.styleable.MyImageView_imageType,TYPE_CIRCLE);
最后记得( array.recycle();)回收TypedArray array释放内存。
三,重写onMeasure方法(设定view的大小)【可不重写】。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(type == TYPE_CIRCLE){
//获取父布局的最小值作为ImageView的宽高
width = Math.min(getMeasuredWidth(),getMeasuredHeight());
//设置圆形圆心点坐标
point = width/weights;
//设置圆半径
radius = width/weights;
//设置当前ImageView控件的宽高
setMeasuredDimension(width/weights*2,width/weights*2);
}
if(type == TYPE_ROUND){
width = Math.min(getMeasuredWidth(),getMeasuredHeight());
setMeasuredDimension(width/2,width/2);
}
}
四,重写onDraw方法,绘制自定义控件内容。
@Override
protected void onDraw(Canvas canvas) {
if(getDrawable() ==null){
if(type == TYPE_CIRCLE){
//在ImageView上无图画圆
canvas.drawCircle(point,point,radius,dPaint);
if(hadFrame){
canvas.drawCircle(point,point,radius,framePaint);
}
}else{
//在ImageView上无图画圆角矩形
canvas.drawRoundRect(rect,borderRadius,borderRadius,dPaint);
}
}else{
setShader();
if(type == TYPE_CIRCLE){
//在ImageView上以位图渲染画圆
canvas.drawCircle(point,point,radius,paint);
if(hadFrame){
canvas.drawCircle(point,point,radius,framePaint);
}
}else{
//在ImageView上以位图渲染画圆角矩形
canvas.drawRoundRect(rect,borderRadius,borderRadius,paint);
}
}
}
设置渲染
private void setShader(){
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
//将drawable转换成bitmap
Bitmap bitmap = drawable2Bitmap(drawable);
//CLAMP(拉伸)、REPEAT(重复)、MIRROR(镜像),shader的拉伸方式为拉伸最后一像素
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//图片缩放,若图片仍小于ImageView则拉伸最后一像素,否则不拉伸
float scale = 1.0f;
float scale1 ;
if(type == TYPE_CIRCLE){
// bitmap.getxxx获取位图的宽高,getxxx获取ImageView的宽高取小值,如果取大值的话,则不能覆盖view
int bitmapWidth = Math.min(bitmap.getWidth(),getHeight());
scale = getWidth()*1.0f/bitmapWidth;//scale=2.0
}else if(type ==TYPE_ROUND){
scale = Math.max(getWidth()*1.0f/bitmap.getWidth(),getHeight()*1.0f/bitmap.getHeight());//scale=2.0
}
matrix.setScale(scale,scale);
bitmapShader.setLocalMatrix(matrix);
paint.setShader(bitmapShader);
if(hadFrame){
Drawable drawable1 = getResources().getDrawable(R.drawable.headframe,null);
Bitmap bitmap1 = drawable2Bitmap(drawable1);
bitmapShader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
int bitmapWidth1 = Math.min(bitmap1.getWidth(),bitmap1.getHeight());
scale1 = getWidth()*1.0f/bitmapWidth1;
matrix1.setScale(scale1,scale1);
bitmapShader1.setLocalMatrix(matrix1);
framePaint.setShader(bitmapShader1);
}
}