android自定义圆角imageview学习

时间:2021-07-03 20:35:04

在面试过程中经常会问你做过什么项目,项目中做了哪些功能啊???怎么实现的呢???
以前项目写过圆角imageview,说实话都是拷贝过来,或者用的框架搞得,如果什么都没有,自己写估计搞不出来,只知道大概实现,哎,还得自己干啊,这就是竞争力!!!!!!!!!!!!!

看了一些文章,理解的圆角imageview实现方式大概有:
1、最简单的就是 使用布局嵌套
2、重写ondraw方法。
图片裁剪—使用setXfermode,创建一个新的圆角bitmap
图片裁剪—优化使用BitmapShader
设置圆角矩形的画布 Path

1、最简单的就是 使用布局嵌套
Framelayout 中2个imageview,一个中间透明,4个角有颜色,进行覆盖,搞一个假的圆角图片,哈哈

<!-- profile image -->
<FrameLayout
android:layout_width="48dp"
android:layout_height="48dp"
>

<ImageView
android:id="@+id/profile_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>

<!-- image corner -->
<ImageView
android:background="@drawable/images_border_radius"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>

</FrameLayout>

一张中间透明, 四个边角带有颜色的遮盖图片即可, 可以使用ps画一个带圆角的矩形, 然后反选并填充边角颜色即可.
其中第一个ImageView为目标图片, 而第2个ImageView则为遮盖层.

2、重写ondraw方法。
我们知道imageview默认是4个直角的,看看源码:

    @Override 
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);//父类View 空方法
if (mDrawable == null) {
return; // couldn't resolve the URI
}

if (mDrawableWidth == 0 || mDrawableHeight == 0) {
return; // nothing to draw (empty bounds)
}

if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
mDrawable.draw(canvas);//1
} else {
int saveCount = canvas.getSaveCount();
canvas.save();

if (mCropToPadding) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
scrollX + mRight - mLeft - mPaddingRight,
scrollY + mBottom - mTop - mPaddingBottom);
}

canvas.translate(mPaddingLeft, mPaddingTop);

if (mDrawMatrix != null) {
canvas.concat(mDrawMatrix);
}
mDrawable.draw(canvas);//2
canvas.restoreToCount(saveCount);
}
}

扩展:drawable 和bitmap转换
http://www.jb51.net/article/81463.htm

这个方法里面可以拿到imageview设置的图片drawable,
源码直接把drawable原图 draw(canvas),
mDrawable.draw(canvas);
将图片画到布上面。

我们可以在之前对图片做处理
图片裁剪—使用setXfermode,创建一个新的圆角bitmap

public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);

final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = 12;

paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}

a.首先创建一个指定高宽的bitmap,作为输出的内容,

b.然后创建一个相同大小的矩形,利用画布绘制时指定圆角角度,这样画布上就有了一个圆角矩形。

c.最后就是设置画笔的剪裁方式为Mode.SRC_IN,将原图叠加到画布上,

这样输出的bitmap就是原图在矩形局域内的内容。
缺点:
这里的剪裁指的是根据原图我们自己生成一张新的bitmap,这个时候指定图片的目标区域为一个圆角局域。这种做法有一点需要生成一个新的bitmap,所以会消耗至少2倍的图片内存。
参考:http://www.cnblogs.com/gaoteng/p/4222207.html

图片裁剪—优化使用BitmapShader

android team的成员写出来的,特点就是不用不需要额外在创建一个图片,这里把原图构造成了一个BitmapShader,然后就可以用画布直接画出圆角的内容。
bitmap —对应 —BitmapShader—对应paint
最终:
bitmap — paint

BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);//bitmap ---对应 ---BitmapShader

Paint paint = new Paint();

paint.setAntiAlias(true);

paint.setShader(shader);//paint --- BitmapShader绑定起来

RectF rect = new RectF(0.0f, 0.0f, width, height);

// rect contains the bounds of the shape

// radius is the radius in pixels of the rounded corners

// paint contains the shader that will texture the shape
//本质就是 画布上 绘制圆角图片,图片包含在 paint中
canvas.drawRoundRect(rect, radius, radius, paint);

上面两个方法都是对图片进行处理,把原图转换成圆角图片,显示在画布上,由于画布是透明的,所以就看出来是圆角图片了!!!!!!!

设置圆角矩形的画布 Path

不把图片变成圆角,修改画布的形状,就是说画布显示区域是
个圆角矩形,这样图片放上去,看上去就是圆角图片了。
好文章参考:
http://www.cnblogs.com/everhad/p/6161083.html
http://blog.csdn.net/zz7zz7zz/article/details/50602748

方法android.graphics.Canvas#clipPath(android.graphics.Path)用来沿着Path指定的路线从目前的canvas裁剪出新的区域的canvas,就是改变了画布的可绘制区域。理解上,就像你拿着剪刀沿着圆环路径裁剪画纸就可以裁剪出一个圆型画纸一样。

Canvas类的一些API是直接绘制内容的操作,另一些是针对canvas(画布)本身做设置的。clip**系列方法就是对画布进行裁剪,之后的绘制(“可以简单地”认为之前通过canvas的绘制已经固定在画布对应存储图像的bitmap上了)都在裁剪后的区域中进行。

使用clipPath()实现圆角矩形的完整代码如下:
private Path mPath = new Path();
@Override
protected void onDraw(Canvas canvas) {

Drawable mDrawable = getDrawable();
if (mDrawable == null)
{
return;
}

if (mDrawable.getIntrinsicWidth() == 0 || mDrawable.getIntrinsicHeight() == 0) {
return; // nothing to draw (empty bounds)
}

canvas.save();
mPath.reset();
canvas.clipPath(mPath); // makes the clip empty
mPath.addRoundRect(mRoundRect, x_radius, y_radius, Path.Direction.CCW);
canvas.clipPath(mPath, Region.Op.REPLACE);

Matrix mDrawMatrix = getImageMatrix();
if (mDrawMatrix != null) {
canvas.concat(mDrawMatrix);
}
mDrawable.draw(canvas);
canvas.restore();
}

这里一步到位
mPath.addRoundRect(mRoundRect, x_radius, y_radius, Path.Direction.CCW); 直接画一个圆角矩形。。。

这是一种修改path的方法,还有方式可以参考
http://blog.csdn.net/u014763302/article/details/44018757
这里是分为4步,每个角画一次,
这个还是需要创建一个新的bitmap

     Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); 
Canvas canvas2 = new Canvas(bitmap);
super.draw(canvas2);
drawLiftUp(canvas2);
drawLiftDown(canvas2);
drawRightUp(canvas2);
drawRightDown(canvas2);
canvas.drawBitmap(bitmap, 0, 0, paint2);
bitmap.recycle();

占用内存。

建议是clip大概这样子。