Picasso实现圆角图片

12

有没有一种合理的方法使用Picasso实现圆角,

  1. 不会显著降低绘制速度
  2. 可以与硬件层一起工作
  3. 不会为每个图像创建额外的位图
  4. 允许将下载的位图调整为目标ImageView的大小

大多数关于Picasso的圆角建议使用转换,但我还没有看到不在转换过程中创建额外位图的示例。

这似乎是因为Picasso只使用位图,而做圆角的技巧利用了可以动态地在相当高效率下绘制圆角的事实(大多数解决方案使用类似http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/的东西)。

使用Volley做这个有点hacky但是可能的,只需将ImageView的类型更改为接受自定义drawable的类型,该drawable画出了圆角。由于Picasso需要位图(至少,只有位图 ->位图转换),因此这是不可能的,因为将drawable转换为位图会在过程中创建位图。

一种解决方案是在自己的分支上修改Picasso,添加位图 -> 可绘制转换,但我想应该有更好的方法来解决这个问题。

我不想在视图顶部绘制9-patch以呈现圆角外观。


1
你试过这个了吗? - AnujAroshA
你看过这个要点了吗?https://gist.github.com/aprock/6213395第28行明显创建了一个新的位图,这正是我想避免的。 - secureboot
我有点困惑,难道你们不会只是将.background设置为一个带有圆角边框的Drawable吗?(也许我混淆了iOS/Android可以做什么... :O) - Fattie
4个回答

28
  1. 这段代码对我工作得很好
    在此输入图片描述

Picasso.with(getApplicationContext())
        .load(sp.getString("image_url", ""))
        .transform(new RoundedTransformation(100, 0))
        .fit()
        .into(userProfileImg);

// 这里是制作的类

    public class RoundedTransformation implements
        com.squareup.picasso.Transformation {
    private final int radius;
    private final int margin; // dp

    // radius is corner radii in dp
    // margin is the board in dp
    public RoundedTransformation(final int radius, final int margin) {
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP));

        Bitmap output = Bitmap.createBitmap(source.getWidth(),
                source.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        canvas.drawRoundRect(new RectF(margin, margin, source.getWidth()
                - margin, source.getHeight() - margin), radius, radius, paint);

        if (source != output) {
            source.recycle();
        }

        return output;
    }

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

5

我也需要类似这样的东西,但需要有边框。我在网上搜索到一个版本(没有圆角)看起来不错,但边框在图像之上,我不喜欢那样。所以我做了自己的版本,边框在图像外。

public class BitmapBorderTransformation implements Transformation {
private int mBorderSize;
private int mCornerRadius = 0;
private int mColor;

public BitmapBorderTransformation(int borderSize, int color) {
    this.mBorderSize = borderSize;
    this.mColor = color;
}

public BitmapBorderTransformation(int borderSize, int cornerRadius, int color) {
    this.mBorderSize = borderSize;
    this.mCornerRadius = cornerRadius;
    this.mColor = color;
}

@Override 
public Bitmap transform(Bitmap source) {
    int width = source.getWidth();
    int height = source.getHeight();

    Bitmap image = Bitmap.createBitmap(width, height, source.getConfig());
    Canvas canvas = new Canvas(image);
    canvas.drawARGB(0, 0, 0, 0);

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Rect rect = new Rect(0, 0, width, height);


    if(this.mCornerRadius == 0) {
        canvas.drawRect(rect, paint);
    }
    else {
        canvas.drawRoundRect(new RectF(rect),
                this.mCornerRadius, this.mCornerRadius, paint);
    }

    paint.setXfermode(new PorterDuffXfermode((PorterDuff.Mode.SRC_IN)));
    canvas.drawBitmap(source, rect, rect, paint);

    Bitmap output;

    if(this.mBorderSize == 0) {
        output = image;
    }
    else {
        width = width + this.mBorderSize * 2;
        height = height + this.mBorderSize * 2;

        output = Bitmap.createBitmap(width, height, source.getConfig());
        canvas.setBitmap(output);
        canvas.drawARGB(0, 0, 0, 0);

        rect = new Rect(0, 0, width, height);

        paint.setXfermode(null);
        paint.setColor(this.mColor);
        paint.setStyle(Paint.Style.FILL);

        canvas.drawRoundRect(new RectF(rect), this.mCornerRadius, this.mCornerRadius, paint);

        canvas.drawBitmap(image, this.mBorderSize, this.mBorderSize, null);
    }

    if(source != output){
        source.recycle();
    }
    return output;
}

@Override 
public String key() {
    return "bitmapBorder(" +
            "borderSize=" + this.mBorderSize + ", " +
            "cornerRadius=" + this.mCornerRadius + ", " +
            "color=" + this.mColor +")";
 }
}

这是一些示例:

同时,您也可以不使用圆角边框:
new BitmapBorderTransformation(3, Color.WHITE);


留下了奇怪的红色颜色,边框对我不起作用 ;( - 68060

3

这个方法适用于任何大小的图像--

1)首先创建一个不同分辨率的空白图像容器 2)然后在运行时通过以下方式获取其高度和宽度-------

BitmapFactory.Options dimensions = new BitmapFactory.Options(); 
dimensions.inJustDecodeBounds = true;
Bitmap mBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon, dimensions);
        int height = dimensions.outHeight;
        int width =  dimensions.outWidth;

3)
Picasso.with(getActivity())
            .load(url)
            .error(R.drawable.image2)
            .placeholder(R.drawable.ic_drawer)
           .resize(width, height )
            .transform(new ImageTrans_roundedcorner())
            .into(imageView1);

4) 现在转换类----

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.Rect;
import android.graphics.RectF;
import com.squareup.picasso.Transformation;

public class ImageTrans_roundedcorner implements Transformation{

    private int mBorderSize=10;
    private int mCornerRadius = 20;
    private int mColor=Color.BLACK;

    @Override
    public Bitmap transform(Bitmap source) {
        // TODO Auto-generated method stub
        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.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, source.getWidth(), source.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = mCornerRadius;

        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(source, rect, rect, paint);

     // draw border
        paint.setColor(color);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth((float) mBorderSize);
        canvas.drawRoundRect(rectF, mCornerRadius, mCornerRadius, paint);
        //-------------------

            if(source != output) source.recycle();

            return output;
    }

    @Override
    public String key() {
        // TODO Auto-generated method stub
        return "grayscaleTransformation()";
    }

}

2

编辑:我建议等待Picasso 2.3版本发布,或者现在就fork他们的github,在那里你可以实际上得到一个BitmapDrawable。

目前我发现的一种方法是,你可以将图片加载到Target对象中,从位图创建自定义drawable,然后将drawable设置到ImageView中,这样它将在不创建新位图的情况下绘制。

但是这种方法有一些缺点:

1)你必须管理Target对象。它们是弱引用(幸运的是),所以你必须自己跟踪它们。可能会出现内存泄漏。

2)当你收到回调时,最好检查一下世界状态是否仍然与图片相关,这也是使用Picasso想要避免的部分。

总之,有几个因素似乎阻止了更好的解决方案。

1)Picasso将位图包装在PicassoDrawables中。这意味着你必须在自定义imageView中处理任意drawable(如果你采用这种方式),或者针对这个类进行特殊处理。 2)PicassoDrawable没有公开源位图,因此你必须将drawable转换为位图(据我所知,需要创建新位图)。 3)没有位图->drawable转换函数(很可能是因为#1原因)。

如果有我遗漏的东西,或者有人想出了更好的解决方案,我很乐意听取。现在我的最佳计划是要么采用上述提出的Target管理方法,要么fork Picasso repo,将PicassoDrawable更改为具有底层位图的公共访问器,并通过此方式将其转换为自定义drawable。


1
Picasso 2.3使PicassoDrawable扩展了BitmapDrawable。它避免了额外的分配,并提供了您想要的API。 - dnkoutso
希望这个月能够发布 :) - dnkoutso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接