33

我有一个Custom ListView包含一个ImageView和的TextView。一切正常。

我想要的是图像显示在列表中的圆角。从 Web 服务我得到矩形形状的图像。但我想在圆角显示它,ImageView如下所示。

在此处输入图像描述

谁能告诉我如何掩盖圆角的图像?

我已经尝试通过创建如下可绘制文件并将其作为 src 应用到ImageView. 但没有什么对我有用。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
   <item>
      <shape android:shape="oval" >
         <solid android:color="#FFFFFF" />
         <padding
            android:bottom="10dp"
            android:left="10dp"
            android:right="10dp"
            android:top="10dp" />
         <corners android:radius="5dp" />
      </shape>
   </item>
   <item>
      <shape android:shape="oval" >
         <padding
            android:bottom="5dp"
            android:left="5dp"
            android:right="5dp"
            android:top="5dp" />
         <solid android:color="#FFFFFF" />
      </shape>
   </item>
</layer-list>

编辑:

在此处输入图像描述

我已应用以下解决方案:

<FrameLayout
    android:id="@+id/imagemaskframe"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp" >

    <ImageView
        android:id="@+id/op_ivpic"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_gravity="center"
        android:scaleType="fitXY" />

    <ImageView
        android:id="@+id/iv_mask_op"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:scaleType="fitXY"
        android:src="@drawable/imgmask" />

</FrameLayout>
4

11 回答 11

33

最好的方法是Canvas使用PorterDuff操作和/或Shaders. 假设您Bitmap的可用并存储在mBitmap.

选项 1:使用着色器。

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

    // Load the bitmap as a shader to the paint.
    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    final Shader shader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    paint.setShader(shader);

    // Draw a circle with the required radius.
    final float halfWidth = canvas.getWidth()/2;
    final float halfHeight = canvas.getHeight()/2;
    final float radius = Math.max(halfWidth, halfHeight);
    canvas.drawCircle(halfWidth, halfHeight, radius, paint);
}

选项 2:使用 PorterDuff 模式。

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

    // Create a circular path.
    final float halfWidth = canvas.getWidth()/2;
    final float halfHeight = canvas.getHeight()/2;
    final float radius = Math.max(halfWidth, halfHeight);
    final Path path = new Path();
    path.addCircle(halfWidth, halfHeight, radius, Path.Direction.CCW);

    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    canvas.drawPath(path, paint);
}

笔记:

  1. 在 onDraw() 调用中创建对象并不好。因此,您最初应该将您的油漆和着色器放在其他地方。当您将图像位图设置为视图时,这可能会完成。
  2. Canvas当它没有硬件纹理支持时,可能需要保存和恢复。这里没有提到围绕它的一般想法。
  3. 记得添加setWillNotDraw(false);到构造函数中。

其他参考:

  1. https://sriramramani.wordpress.com/2012/12/21/shaders/有关于Shaders.
  2. http://mxr.mozilla.org/mozilla-central/source/mobile/android/base/ShapedButton.java用于PathFirefox for Android 中的弯曲按钮。
  3. http://sriramramani.wordpress.com/2012/08/27/constructing-squishy-buttons/提供有关Canvas前 ICS 的保存、恢复和特殊情况的信息。
于 2013-08-30T08:02:17.513 回答
21

我肯定会像其他人一样推荐毕加索。我的一个 Activity 类的这段代码对我有用。它使用了我在 color.xml 中定义的颜色和简单的布局(如下所示)。

       ImageView profile_image = (ImageView) findViewById(R.id.profile_image);
       mContext = profile_image.getContext();

        // ----------------------------------------------------------------
        // apply rounding to image
        // see: https://github.com/vinc3m1/RoundedImageView
        // ----------------------------------------------------------------
        Transformation transformation = new RoundedTransformationBuilder()
                .borderColor(getResources().getColor(R.color.my_special_orange))
                .borderWidthDp(5)
                .cornerRadiusDp(50)
                .oval(false)
                .build();

        Picasso.with(mContext)
                .load("http://{some_url}.jpg")
                .fit()
                .transform(transformation)
                .into(profile_image);

以及对应的Layout文件:

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="120dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:padding="12dp">


        <ImageView
            android:id="@+id/profile_image"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_gravity="center"/>

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_gravity="center"
            android:padding="12dp">


            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:text="First-Name"
                android:id="@+id/profile_first_name"
                />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text="Lastname"
                android:id="@+id/profile_last_name" />
        </LinearLayout>



        </LinearLayout>
</RelativeLayout>

结果如下:

图片

于 2014-11-05T23:16:38.843 回答
17

我建议你使用另一种方法:

一个FrameLayout和两个ImageView可以做到。

<FrameLayout>
    <ImageView />  your image 
    <ImageView />  put a image which has a transparent circle in it
</FrameLayout>

然后可以通过透明圆圈看到您的图像。

于 2013-08-30T08:52:41.490 回答
15

RoundedBitmapDrawable可以将v4 支持库中的A应用于 anImageView以达到预期的效果:

ImageView imageView = (ImageView)findViewById(R.id.imageView);
Bitmap avatar = BitmapFactory.decodeResource(getResources(), R.drawable.avatar);
RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(getResources(), avatar);
roundDrawable.setCircular(true);
imageView.setImageDrawable(roundDrawable);
于 2016-01-26T19:57:39.410 回答
4

一个简单的解决方案,没有黑色背景

public class CircleImageView extends ImageView
{
    public CircleImageView(Context context)
    {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // Create a circular path.
        final float halfWidth = canvas.getWidth()/2;
        final float halfHeight = canvas.getHeight()/2;
        final float radius = Math.max(halfWidth, halfHeight);
        final Path path = new Path();
        path.addCircle(halfWidth, halfHeight, radius, Path.Direction.CCW);

        canvas.clipPath(path);

        super.onDraw(canvas);
    }
}
于 2016-01-25T09:29:55.270 回答
3

请参阅以下代码,这正是您想要的。

https://github.com/vinc3m1/RoundedImageView

正如您所说,如果您不想要自定义视图,请尝试以下想法

创建 9 个带有圆角和透明背景的补丁 .png 图像(如相框)

然后创建具有两个图像视图的相对布局/框架布局,如下所示

<RelativeLayout ....>
   <ImageView android:id="@+id/myImage" ..>
   <ImageView android:id="@+id/myRoundCorner" android:src="@drawable/myRoundCornerdFrame">
</RelativeLayout>

确保两个图像视图除了图像源之外具有相同的属性,并确保源为 myRoundCornerFrame 的图像视图应该在(顶部)另一个图像视图之上。

于 2013-08-30T09:08:24.400 回答
2

试试android-shape-imageview - 它应该可以帮助你。

于 2014-12-16T14:34:41.850 回答
1

对于已经使用 Glide 的用户,可以使用RequestOptions来实现:

RequestOptions requestOptions = new RequestOptions();
requestOptions = requestOptions.transforms(new CenterCrop(), new RoundedCorners(radiusInPixels));
Glide.with(context)
    .load(imageUrl)
    .apply(requestOptions)
    .into(imageView);
于 2018-08-02T19:53:54.573 回答
0

在可绘制的 hdpi 文件夹中创建一个名为 roundimage.xml 的 xml 文件,然后尝试以下代码。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
android:shape="rectangle">
        <solid android:color="@android:color/darker_gray" />
       <corners android:bottomRightRadius="50dip"
        android:bottomLeftRadius="50dip"  
        android:topRightRadius="50dip"
        android:topLeftRadius="50dip"/>
   </shape>

然后将文件包含到您的图像背景中

android:background="@drawable/roundimage"

我要求您根据您的要求更改尺寸和颜色。

请使用此代码

package com.company.app.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;

public class ImageHelper {
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
        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 = pixels;

        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;
    }
}

使用它,因为它有效。

如果你想要方形角落然后使用这个

public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels ,

int w , int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR)
{

Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final float densityMultiplier = context.getResources().getDisplayMetrics().density;

final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);

//make sure that our rounded corner is scaled appropriately
final float roundPx = pixels*densityMultiplier;

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


//draw rectangles over the corners we want to be square
if (squareTL ){
    canvas.drawRect(0, 0, w/2, h/2, paint);
}
if (squareTR ){
    canvas.drawRect(w/2, 0, w, h/2, paint);
}
if (squareBL ){
    canvas.drawRect(0, h/2, w/2, h, paint);
}
if (squareBR ){
    canvas.drawRect(w/2, h/2, w, h, paint);
}

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(input, 0,0, paint);

return output;
}

另外,我覆盖了 ImageView 以将其放入,因此我可以在 xml 中定义它。您可能想在此处添加 super 调用的一些逻辑,但我已对其进行了评论,因为它对我的情况没有帮助。

@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
    Drawable drawable = getDrawable();

    Bitmap b =  ((BitmapDrawable)drawable).getBitmap() ;
    Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

    int w = getWidth(), h = getHeight();


    Bitmap roundBitmap=CropImageView.getRoundedCornerBitmap( getContext(), 
    bitmap,10, w, h , true, false,true, false);
    canvas.drawBitmap(roundBitmap, 0,0 , null);
}
于 2013-08-30T07:54:35.743 回答
0

这是我所做的..但我的 bg img 是矩形的。

        ImageView ivLogo;
        ivLogo=(ImageView)fragment.mRoot.findViewById(R.id.iv_offer_logo);

然后在设置图像时,

      if(response.result.Partner.logo_url != null &&                 !response.result.Partner.logo_url.equals("")){
                 ivLogo.setPadding(3,3,3,3);
               DisplayImageOptions options =
                 WWFunctions.getDisplayImage(0);
            ImageLoader imageLoader = ImageLoader.getInstance();
                    imageLoader.init(ImageLoaderConfiguration.createDefault(mOfferDetailsFragment.getActivity() ));
          imageLoader.displayImage(response.result.Partner.logo_url, ivLogo, options);
        }
于 2013-08-30T12:15:58.377 回答
0

扩展 sriramramani 的答案(包括黑色背景的修复),这是我的简单 ImageView 的全部内容:

public class ExampleImageView extends ImageView {
  public ExampleImageView(Context context) {
    super(context);

    init();
  }

  public ExampleImageView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);

    init();
  }

  public ExampleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    init();
  }

  void init() {
    setWillNotDraw(false);
  }

  @Override
  protected void onDraw(Canvas canvas) {

    int count = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
            Canvas.MATRIX_SAVE_FLAG |
                    Canvas.CLIP_SAVE_FLAG |
                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
                    Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                    Canvas.CLIP_TO_LAYER_SAVE_FLAG);

    super.onDraw(canvas);

    // Create a circular path.
    final float halfWidth = canvas.getWidth()/2;
    final float halfHeight = canvas.getHeight()/2;
    final float radius = Math.max(halfWidth, halfHeight);
    final Path path = new Path();
    path.addCircle(halfWidth, halfHeight, radius, Path.Direction.CCW);

    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    canvas.drawPath(path, paint);

    canvas.restoreToCount(count);
  }
}

一件事-如果我删除此行:

setWillNotDraw(false);

一切仍然有效。不确定是否需要?

于 2017-05-01T03:58:07.720 回答