【问题标题】:Mask ImageView with round corner background用圆角背景遮罩 ImageView
【发布时间】:2013-08-30 07:38:30
【问题描述】:

我有一个Custom ListView,其中包含一个ImageViewTextView。一切正常。

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

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

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

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

【问题讨论】:

  • 这不是重复的。这是关于屏蔽图像,而不是关于以编程方式更改图像。
  • @GrlsHu 你怎么能解决这个问题,请你帮忙解决这个问题
  • @AliAshiq 我已将答案标记为正确,这有助于解决我的问题。
  • @GrIsHu 您遵循了哪个解决方案,我也需要相同的圆圈图像,请您帮助我
  • 查看我的问题。您也可以遵循 Abhishek Pandey 的解决方案。

标签: android android-layout listview imageview


【解决方案1】:

最好的方法是在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 在 Firefox for Android 中使用 Path 弯曲按钮。
  3. http://sriramramani.wordpress.com/2012/08/27/constructing-squishy-buttons/ 提供有关 Canvas 保存、恢复和 ICS 前特殊情况的信息。

【讨论】:

  • 很好的答案!非常感谢! :) 只有设置 XferMode 必须是 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
  • 选项1效果不好,我觉得应该是canvas.drawCircle(halfWidth, halfHeight, radius, >>paint
  • 选项 2 非常适合,其他参考非常有用,谢谢
  • 选项 2 对我来说效果很好,但它有深色背景。知道如何解决吗? stackoverflow.com/q/24054326/513413
  • @Hesam,附加参考 #3 解决了深色背景的问题。
【解决方案2】:

我肯定会像其他人一样推荐毕加索。我的一个 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>

结果如下:

【讨论】:

  • @DavidGeller 嘿,我可以知道它是否以这种方式工作吗?我有一个白色的图标,我想把它放在一个圆圈的顶部。所以基本上它应该设置圆圈的背景而不是设置边框
【解决方案3】:

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

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

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

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

【讨论】:

  • 这将使图像挡住它后面的正方形区域,对吗?
  • 不好的解决方案,如果你想要被阻塞区域后面的透明度
  • 顺序不正确。在 Android 中,代码越晚,视图越接近用户。顺序应该正好相反。很好的解决方案!
  • 这是一个非常智能的解决方案。谢谢你。
  • 我仍然可以看到完整的矩形图像。下面是我的代码 - 跨度>
【解决方案4】:

v4 Support Library 中的RoundedBitmapDrawable 可以应用于ImageView 以达到预期效果:

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • 如果硬件加速开启,clipPath 不起作用。
    【解决方案6】:

    参考下面的代码,正是你想要的。

    https://github.com/vinc3m1/RoundedImageView

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

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

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

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

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

    【讨论】:

    • 我不想为此使用自定义视图。我想在不使用任何自定义库的情况下做到这一点。
    【解决方案7】:

    试试android-shape-imageview - 它应该对你有帮助。

    【讨论】:

      【解决方案8】:

      已经使用 Glide 的可以使用RequestOptions实现效果:

      RequestOptions requestOptions = new RequestOptions();
      requestOptions = requestOptions.transforms(new CenterCrop(), new RoundedCorners(radiusInPixels));
      Glide.with(context)
          .load(imageUrl)
          .apply(requestOptions)
          .into(imageView);
      

      【讨论】:

      • .apply(RequestOptions.circleCropTransform()) 如果您使用的是 glide 4
      【解决方案9】:

      这是我所做的..但我的 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);
              }
      

      【讨论】:

      • 你用过哪个API? DisplayImageOptions 是什么?
      【解决方案10】:

      在可绘制的 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);
      }
      

      【讨论】:

      • 我已经尝试过这样,但图像仍然以矩形形式显示。请参阅我编辑的答案。
      【解决方案11】:

      扩展 sriramani 的答案(包括修复黑色背景),这是我的简单 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);
      

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

      【讨论】:

        猜你喜欢
        • 2018-01-06
        • 1970-01-01
        • 1970-01-01
        • 2015-03-23
        • 1970-01-01
        • 2016-03-16
        • 2014-11-17
        • 1970-01-01
        • 2012-09-04
        相关资源
        最近更新 更多