学习笔记之——Android中的Picasso实现圆形头像、圆角图片工具类

时间:2021-07-03 23:10:55

Android中的Picasso实现圆形头像、圆角图片工具类

一.圆形头像工具类

学习笔记之——Android中的Picasso实现圆形头像、圆角图片工具类

/**
* @author LXL1123
* 配合picaso 圆形头像 工具类
*/
public class CircleTransform implements Transformation {

@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());

int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;

Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}

Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());

Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap,
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);

float r = size / 2f;
canvas.drawCircle(r, r, r, paint);

squaredBitmap.recycle();
return bitmap;
}

@Override
public String key() {
return "circle";
}
}

使用:

Picasso.with(getContext())
.load(saveAvatar)
.transform(new CircleTransform())
.into(img_avatar);

二.圆角图片工具类

学习笔记之——Android中的Picasso实现圆形头像、圆角图片工具类

Corner.java

@Retention(RetentionPolicy.SOURCE)
@IntDef({
Corner.TOP_LEFT, Corner.TOP_RIGHT,
Corner.BOTTOM_LEFT, Corner.BOTTOM_RIGHT
})
public @interface Corner {
int TOP_LEFT = 0;
int TOP_RIGHT = 1;
int BOTTOM_RIGHT = 2;
int BOTTOM_LEFT = 3;
}
RoundedDrawable.java

public class RoundedDrawable extends Drawable {

public static final String TAG = "RoundedDrawable";
public static final int DEFAULT_BORDER_COLOR = Color.BLACK;

private final RectF mBounds = new RectF();
private final RectF mDrawableRect = new RectF();
private final RectF mBitmapRect = new RectF();
private final Bitmap mBitmap;
private final Paint mBitmapPaint;
private final int mBitmapWidth;
private final int mBitmapHeight;
private final RectF mBorderRect = new RectF();
private final Paint mBorderPaint;
private final Matrix mShaderMatrix = new Matrix();
private final RectF mSquareCornersRect = new RectF();

private Shader.TileMode mTileModeX = Shader.TileMode.CLAMP;
private Shader.TileMode mTileModeY = Shader.TileMode.CLAMP;
private boolean mRebuildShader = true;

// [ topLeft, topRight, bottomLeft, bottomRight ]
private float mCornerRadius = 0f;
private final boolean[] mCornersRounded = new boolean[] { true, true, true, true };

private boolean mOval = false;
private float mBorderWidth = 0;
private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
private ScaleType mScaleType = ScaleType.FIT_CENTER;

public RoundedDrawable(Bitmap bitmap) {
mBitmap = bitmap;

mBitmapWidth = bitmap.getWidth();
mBitmapHeight = bitmap.getHeight();
mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight);

mBitmapPaint = new Paint();
mBitmapPaint.setStyle(Paint.Style.FILL);
mBitmapPaint.setAntiAlias(true);

mBorderPaint = new Paint();
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
mBorderPaint.setStrokeWidth(mBorderWidth);
}

public static RoundedDrawable fromBitmap(Bitmap bitmap) {
if (bitmap != null) {
return new RoundedDrawable(bitmap);
} else {
return null;
}
}

public static Drawable fromDrawable(Drawable drawable) {
if (drawable != null) {
if (drawable instanceof RoundedDrawable) {
// just return if it's already a RoundedDrawable
return drawable;
} else if (drawable instanceof LayerDrawable) {
LayerDrawable ld = (LayerDrawable) drawable;
int num = ld.getNumberOfLayers();

// loop through layers to and change to RoundedDrawables if possible
for (int i = 0; i < num; i++) {
Drawable d = ld.getDrawable(i);
ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d));
}
return ld;
}

// try to get a bitmap from the drawable and
Bitmap bm = drawableToBitmap(drawable);
if (bm != null) {
return new RoundedDrawable(bm);
}
}
return drawable;
}

public static Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}

Bitmap bitmap;
int width = Math.max(drawable.getIntrinsicWidth(), 2);
int height = Math.max(drawable.getIntrinsicHeight(), 2);
try {
bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
} catch (Exception e) {
e.printStackTrace();
Log.w(TAG, "Failed to create bitmap from drawable!");
bitmap = null;
}

return bitmap;
}

public Bitmap getSourceBitmap() {
return mBitmap;
}

@Override
public boolean isStateful() {
return mBorderColor.isStateful();
}

@Override
protected boolean onStateChange(int[] state) {
int newColor = mBorderColor.getColorForState(state, 0);
if (mBorderPaint.getColor() != newColor) {
mBorderPaint.setColor(newColor);
return true;
} else {
return super.onStateChange(state);
}
}

private void updateShaderMatrix() {
float scale;
float dx;
float dy;

switch (mScaleType) {
case CENTER:
mBorderRect.set(mBounds);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);

mShaderMatrix.reset();
mShaderMatrix.setTranslate((int) ((mBorderRect.width() - mBitmapWidth) * 0.5f + 0.5f),
(int) ((mBorderRect.height() - mBitmapHeight) * 0.5f + 0.5f));
break;

case CENTER_CROP:
mBorderRect.set(mBounds);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);

mShaderMatrix.reset();

dx = 0;
dy = 0;

if (mBitmapWidth * mBorderRect.height() > mBorderRect.width() * mBitmapHeight) {
scale = mBorderRect.height() / (float) mBitmapHeight;
dx = (mBorderRect.width() - mBitmapWidth * scale) * 0.5f;
} else {
scale = mBorderRect.width() / (float) mBitmapWidth;
dy = (mBorderRect.height() - mBitmapHeight * scale) * 0.5f;
}

mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth / 2,
(int) (dy + 0.5f) + mBorderWidth / 2);
break;

case CENTER_INSIDE:
mShaderMatrix.reset();

if (mBitmapWidth <= mBounds.width() && mBitmapHeight <= mBounds.height()) {
scale = 1.0f;
} else {
scale = Math.min(mBounds.width() / (float) mBitmapWidth,
mBounds.height() / (float) mBitmapHeight);
}

dx = (int) ((mBounds.width() - mBitmapWidth * scale) * 0.5f + 0.5f);
dy = (int) ((mBounds.height() - mBitmapHeight * scale) * 0.5f + 0.5f);

mShaderMatrix.setScale(scale, scale);
mShaderMatrix.postTranslate(dx, dy);

mBorderRect.set(mBitmapRect);
mShaderMatrix.mapRect(mBorderRect);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
break;

default:
case FIT_CENTER:
mBorderRect.set(mBitmapRect);
mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.CENTER);
mShaderMatrix.mapRect(mBorderRect);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
break;

case FIT_END:
mBorderRect.set(mBitmapRect);
mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.END);
mShaderMatrix.mapRect(mBorderRect);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
break;

case FIT_START:
mBorderRect.set(mBitmapRect);
mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.START);
mShaderMatrix.mapRect(mBorderRect);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
break;

case FIT_XY:
mBorderRect.set(mBounds);
mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
mShaderMatrix.reset();
mShaderMatrix.setRectToRect(mBitmapRect, mBorderRect, Matrix.ScaleToFit.FILL);
break;
}

mDrawableRect.set(mBorderRect);
}

@Override
protected void onBoundsChange(@NonNull Rect bounds) {
super.onBoundsChange(bounds);

mBounds.set(bounds);

updateShaderMatrix();
}

@Override
public void draw(@NonNull Canvas canvas) {
if (mRebuildShader) {
BitmapShader bitmapShader = new BitmapShader(mBitmap, mTileModeX, mTileModeY);
if (mTileModeX == Shader.TileMode.CLAMP && mTileModeY == Shader.TileMode.CLAMP) {
bitmapShader.setLocalMatrix(mShaderMatrix);
}
mBitmapPaint.setShader(bitmapShader);
mRebuildShader = false;
}

if (mOval) {
if (mBorderWidth > 0) {
canvas.drawOval(mDrawableRect, mBitmapPaint);
canvas.drawOval(mBorderRect, mBorderPaint);
} else {
canvas.drawOval(mDrawableRect, mBitmapPaint);
}
} else {
if (any(mCornersRounded)) {
float radius = mCornerRadius;
if (mBorderWidth > 0) {
canvas.drawRoundRect(mDrawableRect, radius, radius, mBitmapPaint);
canvas.drawRoundRect(mBorderRect, radius, radius, mBorderPaint);
redrawBitmapForSquareCorners(canvas);
redrawBorderForSquareCorners(canvas);
} else {
canvas.drawRoundRect(mDrawableRect, radius, radius, mBitmapPaint);
redrawBitmapForSquareCorners(canvas);
}
} else {
canvas.drawRect(mDrawableRect, mBitmapPaint);
if (mBorderWidth > 0) {
canvas.drawRect(mBorderRect, mBorderPaint);
}
}
}
}

private void redrawBitmapForSquareCorners(Canvas canvas) {
if (all(mCornersRounded)) {
// no square corners
return;
}

if (mCornerRadius == 0) {
return; // no round corners
}

float left = mDrawableRect.left;
float top = mDrawableRect.top;
float right = left + mDrawableRect.width();
float bottom = top + mDrawableRect.height();
float radius = mCornerRadius;

if (!mCornersRounded[Corner.TOP_LEFT]) {
mSquareCornersRect.set(left, top, left + radius, top + radius);
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
}

if (!mCornersRounded[Corner.TOP_RIGHT]) {
mSquareCornersRect.set(right - radius, top, right, radius);
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
}

if (!mCornersRounded[Corner.BOTTOM_RIGHT]) {
mSquareCornersRect.set(right - radius, bottom - radius, right, bottom);
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
}

if (!mCornersRounded[Corner.BOTTOM_LEFT]) {
mSquareCornersRect.set(left, bottom - radius, left + radius, bottom);
canvas.drawRect(mSquareCornersRect, mBitmapPaint);
}
}

private void redrawBorderForSquareCorners(Canvas canvas) {
if (all(mCornersRounded)) {
// no square corners
return;
}

if (mCornerRadius == 0) {
return; // no round corners
}

float left = mDrawableRect.left;
float top = mDrawableRect.top;
float right = left + mDrawableRect.width();
float bottom = top + mDrawableRect.height();
float radius = mCornerRadius;
float offset = mBorderWidth / 2;

if (!mCornersRounded[Corner.TOP_LEFT]) {
canvas.drawLine(left - offset, top, left + radius, top, mBorderPaint);
canvas.drawLine(left, top - offset, left, top + radius, mBorderPaint);
}

if (!mCornersRounded[Corner.TOP_RIGHT]) {
canvas.drawLine(right - radius - offset, top, right, top, mBorderPaint);
canvas.drawLine(right, top - offset, right, top + radius, mBorderPaint);
}

if (!mCornersRounded[Corner.BOTTOM_RIGHT]) {
canvas.drawLine(right - radius - offset, bottom, right + offset, bottom, mBorderPaint);
canvas.drawLine(right, bottom - radius, right, bottom, mBorderPaint);
}

if (!mCornersRounded[Corner.BOTTOM_LEFT]) {
canvas.drawLine(left - offset, bottom, left + radius, bottom, mBorderPaint);
canvas.drawLine(left, bottom - radius, left, bottom, mBorderPaint);
}
}

@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}

@Override
public int getAlpha() {
return mBitmapPaint.getAlpha();
}

@Override
public void setAlpha(int alpha) {
mBitmapPaint.setAlpha(alpha);
invalidateSelf();
}

@Override
public ColorFilter getColorFilter() {
return mBitmapPaint.getColorFilter();
}

@Override
public void setColorFilter(ColorFilter cf) {
mBitmapPaint.setColorFilter(cf);
invalidateSelf();
}

@Override
public void setDither(boolean dither) {
mBitmapPaint.setDither(dither);
invalidateSelf();
}

@Override
public void setFilterBitmap(boolean filter) {
mBitmapPaint.setFilterBitmap(filter);
invalidateSelf();
}

@Override
public int getIntrinsicWidth() {
return mBitmapWidth;
}

@Override
public int getIntrinsicHeight() {
return mBitmapHeight;
}

/**
* @return the corner radius.
*/
public float getCornerRadius() {
return mCornerRadius;
}

/**
* @param corner the specific corner to get radius of.
* @return the corner radius of the specified corner.
*/
public float getCornerRadius(@Corner int corner) {
return mCornersRounded[corner] ? mCornerRadius : 0f;
}

/**
* Sets all corners to the specified radius.
*
* @param radius the radius.
* @return the {@link RoundedDrawable} for chaining.
*/
public RoundedDrawable setCornerRadius(float radius) {
setCornerRadius(radius, radius, radius, radius);
return this;
}

/**
* Sets the corner radius of one specific corner.
*
* @param corner the corner.
* @param radius the radius.
* @return the {@link RoundedDrawable} for chaining.
*/
public RoundedDrawable setCornerRadius(@Corner int corner, float radius) {
if (radius != 0 && mCornerRadius != 0 && mCornerRadius != radius) {
throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
}

if (radius == 0) {
if (only(corner, mCornersRounded)) {
mCornerRadius = 0;
}
mCornersRounded[corner] = false;
} else {
if (mCornerRadius == 0) {
mCornerRadius = radius;
}
mCornersRounded[corner] = true;
}

return this;
}

/**
* Sets the corner radii of all the corners.
*
* @param topLeft top left corner radius.
* @param topRight top right corner radius
* @param bottomRight bototm right corner radius.
* @param bottomLeft bottom left corner radius.
* @return the {@link RoundedDrawable} for chaining.
*/
public RoundedDrawable setCornerRadius(float topLeft, float topRight, float bottomRight,
float bottomLeft) {
Set<Float> radiusSet = new HashSet<>(4);
radiusSet.add(topLeft);
radiusSet.add(topRight);
radiusSet.add(bottomRight);
radiusSet.add(bottomLeft);

radiusSet.remove(0f);

if (radiusSet.size() > 1) {
throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
}

if (!radiusSet.isEmpty()) {
float radius = radiusSet.iterator().next();
if (Float.isInfinite(radius) || Float.isNaN(radius) || radius < 0) {
throw new IllegalArgumentException("Invalid radius value: " + radius);
}
mCornerRadius = radius;
} else {
mCornerRadius = 0f;
}

mCornersRounded[Corner.TOP_LEFT] = topLeft > 0;
mCornersRounded[Corner.TOP_RIGHT] = topRight > 0;
mCornersRounded[Corner.BOTTOM_RIGHT] = bottomRight > 0;
mCornersRounded[Corner.BOTTOM_LEFT] = bottomLeft > 0;
return this;
}

public float getBorderWidth() {
return mBorderWidth;
}

public RoundedDrawable setBorderWidth(float width) {
mBorderWidth = width;
mBorderPaint.setStrokeWidth(mBorderWidth);
return this;
}

public int getBorderColor() {
return mBorderColor.getDefaultColor();
}

public RoundedDrawable setBorderColor(@ColorInt int color) {
return setBorderColor(ColorStateList.valueOf(color));
}

public ColorStateList getBorderColors() {
return mBorderColor;
}

public RoundedDrawable setBorderColor(ColorStateList colors) {
mBorderColor = colors != null ? colors : ColorStateList.valueOf(0);
mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
return this;
}

public boolean isOval() {
return mOval;
}

public RoundedDrawable setOval(boolean oval) {
mOval = oval;
return this;
}

public ScaleType getScaleType() {
return mScaleType;
}

public RoundedDrawable setScaleType(ScaleType scaleType) {
if (scaleType == null) {
scaleType = ScaleType.FIT_CENTER;
}
if (mScaleType != scaleType) {
mScaleType = scaleType;
updateShaderMatrix();
}
return this;
}

public Shader.TileMode getTileModeX() {
return mTileModeX;
}

public RoundedDrawable setTileModeX(Shader.TileMode tileModeX) {
if (mTileModeX != tileModeX) {
mTileModeX = tileModeX;
mRebuildShader = true;
invalidateSelf();
}
return this;
}

public Shader.TileMode getTileModeY() {
return mTileModeY;
}

public RoundedDrawable setTileModeY(Shader.TileMode tileModeY) {
if (mTileModeY != tileModeY) {
mTileModeY = tileModeY;
mRebuildShader = true;
invalidateSelf();
}
return this;
}

private static boolean only(int index, boolean[] booleans) {
for (int i = 0, len = booleans.length; i < len; i++) {
if (booleans[i] != (i == index)) {
return false;
}
}
return true;
}

private static boolean any(boolean[] booleans) {
for (boolean b : booleans) {
if (b) { return true; }
}
return false;
}

private static boolean all(boolean[] booleans) {
for (boolean b : booleans) {
if (b) { return false; }
}
return true;
}

public Bitmap toBitmap() {
return drawableToBitmap(this);
}
}
RoundedTransformationBuilder.java

public final class RoundedTransformationBuilder {

private final DisplayMetrics mDisplayMetrics;

private float[] mCornerRadii = new float[] { 0, 0, 0, 0 };

private boolean mOval = false;
private float mBorderWidth = 0;
private ColorStateList mBorderColor =
ColorStateList.valueOf(RoundedDrawable.DEFAULT_BORDER_COLOR);
private ImageView.ScaleType mScaleType = ImageView.ScaleType.FIT_CENTER;

public RoundedTransformationBuilder() {
mDisplayMetrics = Resources.getSystem().getDisplayMetrics();
}

public RoundedTransformationBuilder scaleType(ImageView.ScaleType scaleType) {
mScaleType = scaleType;
return this;
}

/**
* Set corner radius for all corners in px.
*
* @param radius the radius in px
* @return the builder for chaining.
*/
public RoundedTransformationBuilder cornerRadius(float radius) {
mCornerRadii[Corner.TOP_LEFT] = radius;
mCornerRadii[Corner.TOP_RIGHT] = radius;
mCornerRadii[Corner.BOTTOM_RIGHT] = radius;
mCornerRadii[Corner.BOTTOM_LEFT] = radius;
return this;
}

/**
* Set corner radius for a specific corner in px.
*
* @param corner the corner to set.
* @param radius the radius in px.
* @return the builder for chaning.
*/
public RoundedTransformationBuilder cornerRadius(int corner, float radius) {
mCornerRadii[corner] = radius;
return this;
}

/**
* Set corner radius for all corners in density independent pixels.
*
* @param radius the radius in density independent pixels.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder cornerRadiusDp(float radius) {
return cornerRadius(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, mDisplayMetrics));
}

/**
* Set corner radius for a specific corner in density independent pixels.
*
* @param corner the corner to set
* @param radius the radius in density independent pixels.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder cornerRadiusDp(int corner, float radius) {
return cornerRadius(corner,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, mDisplayMetrics));
}

/**
* Set the border width in pixels.
*
* @param width border width in pixels.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder borderWidth(float width) {
mBorderWidth = width;
return this;
}

/**
* Set the border width in density independent pixels.
*
* @param width border width in density independent pixels.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder borderWidthDp(float width) {
mBorderWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, mDisplayMetrics);
return this;
}

/**
* Set the border color.
*
* @param color the color to set.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder borderColor(int color) {
mBorderColor = ColorStateList.valueOf(color);
return this;
}

/**
* Set the border color as a {@link ColorStateList}.
*
* @param colors the {@link ColorStateList} to set.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder borderColor(ColorStateList colors) {
mBorderColor = colors;
return this;
}

/**
* Sets whether the image should be oval or not.
*
* @param oval if the image should be oval.
* @return the builder for chaining.
*/
public RoundedTransformationBuilder oval(boolean oval) {
mOval = oval;
return this;
}

/**
* Creates a {@link Transformation} for use with picasso.
*
* @return the {@link Transformation}
*/
public Transformation build() {
return new Transformation() {
@Override public Bitmap transform(Bitmap source) {
Bitmap transformed = RoundedDrawable.fromBitmap(source)
.setScaleType(mScaleType)
.setCornerRadius(mCornerRadii[0], mCornerRadii[1], mCornerRadii[2], mCornerRadii[3])
.setBorderWidth(mBorderWidth)
.setBorderColor(mBorderColor)
.setOval(mOval)
.toBitmap();
if (!source.equals(transformed)) {
source.recycle();
}
return transformed;
}

@Override public String key() {
return "r:" + Arrays.toString(mCornerRadii)
+ "b:" + mBorderWidth
+ "c:" + mBorderColor
+ "o:" + mOval;
}
};
}
}

使用:

//picasso 弧度圆角头像
Transformation transformation = new RoundedTransformationBuilder()
.borderColor(Color.TRANSPARENT)
.borderWidthDp(0)
.cornerRadiusDp(6)//圆角角度 像素
.oval(false)
.build();
Picasso.with(this).load(avatar).transform(transformation).placeholder(R.drawable.default_avatar).into(holder.avatar);

圆角图片相关类下载:http://download.csdn.net/detail/lxlyhm/9823682




感谢

http://blog.csdn.net/u014005316/article/details/54138429