如何使用Glide库将图像裁剪成圆形?

238

有人知道如何使用Glide显示圆角图片吗?

我正在使用Glide加载一张图片,但是不知道如何将圆角参数传递给这个库。

我需要像以下示例一样显示图片:

图片描述


2
我使用了 https://github.com/hdodenhof/CircleImageView 来实现圆形图片视图。 - MilapTank
2
我知道如何使用Glide库与CircleImageView,但我正在寻找只使用Glide库的可能方法。Glide库中是否有任何方法可以实现这一点,或者它不支持此功能? - SBotirov
28个回答

591

Glide V4:

    Glide.with(context)
        .load(url)
        .circleCrop()
        .into(imageView);

Glide V3:

您可以使用RoundedBitmapDrawable和Glide实现圆形图像,不需要自定义ImageView。

 Glide.with(context).load(url).asBitmap().centerCrop().into(new BitmapImageViewTarget(imageView) {
        @Override
        protected void setResource(Bitmap resource) {
            RoundedBitmapDrawable circularBitmapDrawable =
                    RoundedBitmapDrawableFactory.create(context.getResources(), resource);
            circularBitmapDrawable.setCircular(true);
            imageView.setImageDrawable(circularBitmapDrawable);
        }
    });

7
不过,这并没有创建边界。 - ZakTaccardi
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Greg Ennis
12
将背景设置为椭圆形可绘制形状,并给ImageView添加填充以创建边框。 - Lalit Jadav
2
如果您遇到问题,请检查Roman Samoylenko提供的下一个可行解决方案。 - Pabel
1
你可能想用.circleCrop()代替.centerCrop() - Thanasis Kapelonis
显示剩余10条评论

70

看看这篇文章,glide vs picasso...
编辑:链接的文章没有指出这些库中一个重要的区别。Glide 会自动回收。请参阅TWiStErRob 的评论了解更多。

Glide.with(this).load(URL).transform(new CircleTransform(context)).into(imageView);

public static class CircleTransform extends BitmapTransformation {
    public CircleTransform(Context context) {
        super(context);
    }

    @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }

    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

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

        // TODO this could be acquired from the pool too
        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

    @Override public String getId() {
        return getClass().getName();
    }
} 

请注意不要像代码中展示的那样使用public String getId(),因为它会为所有图像返回相同的ID,这可能会导致Glide在没有转换的情况下设置旧的圆形图像,而正确的图像则不会被设置!我不知道Glide是如何工作的,但似乎它会缓存图像转换(为了避免硬计算)。而ID被用作转换后图像的ID。我在构造函数中添加了一个图像的URL,并使提到的方法返回结果ID,如:this.id = String.format("%s:%s",this.getClass().getSimpleName(),id); - Stan
2
Stan对转换ID的唯一要求是它们在所有转换中都是唯一的,因此这里的使用是正确的。缓存键将包括源ID和转换ID,因此转换ID是一个混合而不是替换。请参见https://github.com/bumptech/glide/wiki/Caching-and-Cache-Invalidation#cache-keys - Sam Judd
我修复了[Glide#408](https://github.com/bumptech/glide/issues/408)中发现的资源重用问题,并且还注意到Glide 4.0将内置圆形转换。 - TWiStErRob
4
有没有一种方法可以对占位符应用变换? - Sinigami
据我所知,没有这样的功能。占位符是同步应用的,而转换本质上是异步的。 - Teovald
显示剩余3条评论

69

最简单的方式(需要Glide 4.x.x)

Glide.with(context).load(uri).apply(RequestOptions.circleCropTransform()).into(imageView)

这甚至无法编译... RequestOptions()? - Rafael Lima
3
@RafaelLima 这是用 Kotlin 写的。 - Roman Samoilenko
2
请注意,.apply().load()之后。 - Johnny Five
是 RequestOptions.circleCropTransform(),而不是 RequestOptions()。 - Smiles
2
你需要写Glide.with(context).load(uri).apply(circleCrop()).into(imageView)注意apply函数。 - Jaspal

34

尝试这种方法

代码

Glide.with(this)
    .load(R.drawable.thumbnail)
    .bitmapTransform(new CropCircleTransformation(this))
    .into(mProfile);

XML

<ImageView
  android:id="@+id/img_profile"
  android:layout_width="76dp"
  android:layout_height="76dp"
  android:background="@drawable/all_circle_white_bg"
  android:padding="1dp"/>

all_circle_white_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <shape android:shape="oval">
      <solid android:color="@android:color/white"/>
  </shape>
  </item>
</selector>

这个答案应该被接受。它提供了你所需要的一切,非常好!我还想补充一点,你可以在 XML 中添加填充,这样你的图像就不会触碰到边框 ;) - Kratos

11

非常简单,我看过 Glide 库,它是一个非常好的库。同时,也有一个基于 Google 的 Volley 库的文章。

使用这个库来创建圆形图片视图。

https://github.com/hdodenhof/CircleImageView

//对于一个简单的视图:

 @Override
 public void onCreate(Bundle savedInstanceState) {
  ...

  CircleImageView civProfilePic = (CircleImageView)findViewById(R.id.ivProfile);
  Glide.load("http://goo.gl/h8qOq7").into(civProfilePic);
}

//对于列表:

@Override
public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
 if (recycled == null) {
    myImageView = (CircleImageView) inflater.inflate(R.layout.my_image_view,
            container, false);
} else {
    myImageView = (CircleImageView) recycled;
}

String url = myUrls.get(position);

Glide.load(url)
    .centerCrop()
    .placeholder(R.drawable.loading_spinner)
    .animate(R.anim.fade_in)
    .into(myImageView);

  return myImageView;
}

以及在XML中

<de.hdodenhof.circleimageview.CircleImageView
   android:id="@+id/ivProfile
   android:layout_width="160dp"
   android:layout_height="160dp"
   android:layout_centerInParent="true"
   android:src="@drawable/hugh"
   app:border_width="2dp"
   app:border_color="@color/dark" />

2
就像在之前的回答评论中提到的那样,这种方式也不太好用。至少对于'de.hdodenhof:circleimageview:1.2.2' + 'com.github.bumptech.glide:glide:3.5.2'是如此。已经检查过了,再次确认。同样的问题也存在于glide 3.4.+和circleimageview 1.2.1中。 - Stan
使用.centerCrop()对我有用。在 DiamondImageView 上使用 .asBitmap() 更是 如此。 - felippe
1
需要在 Glide 上调用 .dontAnimate() 方法,这是不可接受的。 - Greg Ennis
+1 但请注意 使用 Glide 加载互联网图片 - hedgehog

10
其他解决方案对我都不起作用。我发现它们都有明显的缺点:
  • 使用glide转换的解决方案无法与占位符一起使用
  • 使用圆形图像视图的解决方案无法与动画(即淡入淡出)一起使用
  • 使用一个裁剪其子项的父级的通用方法(即此处已被接受的答案)在使用glide时效果不佳

真的很有趣,在瞎摸索后,我发现了关于圆角和圆形的Fresco库页面,其中列出了基本上相同的限制,并得出以下声明:

在Android上没有真正好的圆角解决方案,人们必须在前述的权衡之间选择

难以置信,在现在这个时候我们仍然没有真正的解决方案。我有一个基于我上面提到的链接的备选方案。这种方法的缺点是它假定你的背景是纯色的(边角并不是真正透明的)。你可以像这样使用它:

<RoundedCornerLayout ...>
    <ImageView ...>
</RoundedCornerLayout>

要点在这里,完整代码在此处:

public class RoundedCornerLayout extends RelativeLayout {
    private Bitmap maskBitmap;
    private Paint paint;
    private float cornerRadius;

    public RoundedCornerLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

    public RoundedCornerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        setWillNotDraw(false);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        if (maskBitmap == null) {
            // This corner radius assumes the image width == height and you want it to be circular
            // Otherwise, customize the radius as needed
            cornerRadius = canvas.getWidth() / 2;
            maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
        }

        canvas.drawBitmap(maskBitmap, 0f, 0f, paint);
    }

    private Bitmap createMask(int width, int height) {
        Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mask);

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE); // TODO set your background color as needed

        canvas.drawRect(0, 0, width, height, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);

        return mask;
    }
}

8
根据这个答案,两种语言的最简单方法如下: Kotlin:
Glide.with(context).load(uri).apply(RequestOptions().circleCrop()).into(imageView)

Java:

Glide.with(context).load(uri).apply(new RequestOptions().circleCrop()).into(imageView)

这适用于 Glide 4.X.X 版本。


8

现在在Glide V4中,您可以直接使用CircleCrop()。

Glide.with(fragment)
  .load(url)
  .circleCrop()
  .into(imageView);

内置类型

  • 居中裁剪
  • 适应中心
  • 圆形裁剪

6

使用这个转换,它会正常工作。

public class CircleTransform extends BitmapTransformation {
public CircleTransform(Context context) {
    super(context);
}

@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
    return circleCrop(pool, toTransform);
}

private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
    if (source == null) return null;

    int borderColor = ColorUtils.setAlphaComponent(Color.WHITE, 0xFF);
    int borderRadius = 3;

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

    // TODO this could be acquired from the pool too
    Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
    if (squared != source) {
        source.recycle();
    }

    Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
    if (result == null) {
        result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
    }

    Canvas canvas = new Canvas(result);
    Paint paint = new Paint();
    paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
    paint.setAntiAlias(true);
    float r = size / 2f;
    canvas.drawCircle(r, r, r, paint);

    // Prepare the background
    Paint paintBg = new Paint();
    paintBg.setColor(borderColor);
    paintBg.setAntiAlias(true);

    // Draw the background circle
    canvas.drawCircle(r, r, r, paintBg);

    // Draw the image smaller than the background so a little border will be seen
    canvas.drawCircle(r, r, r - borderRadius, paint);

    squared.recycle();

    return result;
}

@Override
public String getId() {
    return getClass().getName();
}} 

6

对于 Glide 4.x.x 版本:

使用

Glide
  .with(context)
  .load(uri)
  .apply(
      RequestOptions()
        .circleCrop())
  .into(imageView)

根据 doc 中的说明:

圆形图片:CircleImageView/CircularImageView/RoundedImageView已知在使用TransitionDrawable(.crossFade() with .thumbnail() or .placeholder())和动态GIF时存在问题,建议使用BitmapTransformation(.circleCrop() 将在 v4 版本中提供)或 .dontAnimate() 来解决这个问题。


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