【问题标题】:How to create round corner image using volley library android如何使用 volley 库 android 创建圆角图像
【发布时间】:2014-10-06 15:33:30
【问题描述】:

我正在从服务器获取具有方形形状的图像 url,我必须将其制作成圆角图像。实际上我正在使用 volley 库,我知道如何使用通用图像加载器和 picasso 库创建圆角图像。在 volley 库中我我正在像 setimageUrl 一样在网络 imageview 中设置图像,请帮助我

 holder.ivImage.setImageUrl(url, imageLoader);

【问题讨论】:

  • Volley 是网络库,与处理图像无关。检查这个答案:stackoverflow.com/questions/16208365/…
  • @mata 是的,但是如果用户使用 volley 库中的 NetworkImageView,他需要知道如何操作图像。您链接的答案在其“onDraw()”中使用“getDrawable()”来访问图像,但只有在图像是从可绘制资源设置的情况下才会设置可绘制对象。 NetworkImageView中只设置了一个图片url,当图片下载完成后,调用setBitmap设置图片,drawable不设置。

标签: android android-volley networkimageview


【解决方案1】:

我找到了一个使 imageview 圆形的源代码,例如https://github.com/hdodenhof/CircleImageView这是扩展imageview,我只是让它扩展NetworkImageView。一切对我来说都很好。如果您不想使用上述圆形图像视图,则必须扩展 NetworkImageView 类并自定义以满足您的需求。

【讨论】:

  • 这是怎么做到的?您是否只是将代码复制并粘贴到您的项目中?如果是这样,您是如何在布局 xml 中引用您的类的?
  • 我复制了代码。我在布局中这样引用
  • 效果很好,感谢 Prashanth。然后我必须添加一个属性 xml 并在我的 XML 中使用 custom:attr_name="attr_value" 对其进行定位
  • @PrashanthDebbadwar 哇,我用的是Volley's NetworkImageView 并希望它是圆形的。我使用这个类和extends 它到NetworkImageView 而不是ImageView 并且它有效!谢啦。 .您可以接受这个答案,也许您可​​以像我一样尝试一下。 @彼得
  • 注意 CircleImageView 只支持 CENTER_CROP。我们不能改变它。它适用于个人资料图片,但如果您有任何其他要求,则无济于事。
【解决方案2】:

您需要扩展 NetworkImageView 类并创建自己的视图

Java:CircularNetworkImageView

import android.content.Context;
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;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;


import com.android.volley.toolbox.NetworkImageView;



public class CircularNetworkImageView extends NetworkImageView {
    Context mContext;

    public CircularNetworkImageView(Context context) {
        super(context);
        mContext = context;
    }

    public CircularNetworkImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        mContext = context;
    }

    public CircularNetworkImageView(Context context, AttributeSet attrs,
                                    int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        if(bm==null) return;
        setImageDrawable(new BitmapDrawable(mContext.getResources(),
                getCircularBitmap(bm)));
    }

    /**
     * Creates a circular bitmap and uses whichever dimension is smaller to determine the width
     * <br/>Also constrains the circle to the leftmost part of the image
     *
     * @param bitmap
     * @return bitmap
     */
    public Bitmap getCircularBitmap(Bitmap bitmap) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        int width = bitmap.getWidth();
        if(bitmap.getWidth()>bitmap.getHeight())
            width = bitmap.getHeight();
        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, width, width);
        final RectF rectF = new RectF(rect);
        final float roundPx = width / 2;

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

XML

<com.example.own.CircularNetworkImageView
        android:id="@+id/image"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_marginRight="10dp"/>

用法:

    CircularNetworkImageView image = (CircularNetworkImageView) view.findViewById(R.id.image);
    private ImageLoader netImageLoader=AppController.getInstance().getImageLoader();
    image.setImageUrl("imageurl", netImageLoader);

【讨论】:

    【解决方案3】:

    您可以创建一个扩展 NetworkImageView(Volley) 的自定义类。

    Code

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapShader;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.Shader;
    import android.graphics.drawable.Drawable;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    
    import com.android.volley.VolleyError;
    import com.android.volley.toolbox.ImageLoader;
    import com.android.volley.toolbox.ImageLoader.ImageContainer;
    import com.android.volley.toolbox.ImageLoader.ImageListener;
    
    import java.lang.reflect.InvocationTargetException;
    
    /**
     * Handles fetching an image from a URL as well as the life-cycle of the
     * associated request.
     */
    public class CircledNetworkImageView extends ImageView {
        public boolean mCircled;
    
        /** The URL of the network image to load */
        private String mUrl;
    
        /**
         * Resource ID of the image to be used as a placeholder until the network image is loaded.
         */
        private int mDefaultImageId;
    
        /**
         * Resource ID of the image to be used if the network response fails.
         */
        private int mErrorImageId;
    
        /** Local copy of the ImageLoader. */
        private ImageLoader mImageLoader;
    
        /** Current ImageContainer. (either in-flight or finished) */
        private ImageContainer mImageContainer;
    
        public CircledNetworkImageView(Context context) {
            this(context, null);
        }
    
        public CircledNetworkImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CircledNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        /**
         * Sets URL of the image that should be loaded into this view. Note that calling this will
         * immediately either set the cached image (if available) or the default image specified by
         * {@link CircledNetworkImageView#setDefaultImageResId(int)} on the view.
         *
         * NOTE: If applicable, {@link CircledNetworkImageView#setDefaultImageResId(int)} and
         * {@link CircledNetworkImageView#setErrorImageResId(int)} should be called prior to calling
         * this function.
         *
         * @param url The URL that should be loaded into this ImageView.
         * @param imageLoader ImageLoader that will be used to make the request.
         */
        public void setImageUrl(String url, ImageLoader imageLoader) {
            mUrl = url;
            mImageLoader = imageLoader;
            // The URL has potentially changed. See if we need to load it.
            loadImageIfNecessary(false);
        }
    
        /**
         * Sets the default image resource ID to be used for this view until the attempt to load it
         * completes.
         */
        public void setDefaultImageResId(int defaultImage) {
            mDefaultImageId = defaultImage;
        }
    
        /**
         * Sets the error image resource ID to be used for this view in the event that the image
         * requested fails to load.
         */
        public void setErrorImageResId(int errorImage) {
            mErrorImageId = errorImage;
        }
    
        /**
         * Loads the image for the view if it isn't already loaded.
         * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
         */
        private void loadImageIfNecessary(final boolean isInLayoutPass) {
            int width = getWidth();
            int height = getHeight();
    
            boolean isFullyWrapContent = getLayoutParams() != null
                    && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT
                    && getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
            // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
            // view, hold off on loading the image.
            if (width == 0 && height == 0 && !isFullyWrapContent) {
                return;
            }
    
            // if the URL to be loaded in this view is empty, cancel any old requests and clear the
            // currently loaded image.
            if (TextUtils.isEmpty(mUrl)) {
                if (mImageContainer != null) {
                    mImageContainer.cancelRequest();
                    mImageContainer = null;
                }
                setImageBitmap(null);
                return;
            }
    
            // if there was an old request in this view, check if it needs to be canceled.
            if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
                if (mImageContainer.getRequestUrl().equals(mUrl)) {
                    // if the request is from the same URL, return.
                    return;
                } else {
                    // if there is a pre-existing request, cancel it if it's fetching a different URL.
                    mImageContainer.cancelRequest();
                    setImageBitmap(null);
                }
            }
    
            // The pre-existing content of this view didn't match the current URL. Load the new image
            // from the network.
            ImageContainer newContainer = mImageLoader.get(mUrl,
                    new ImageListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            if (mErrorImageId != 0) {
                                setImageResource(mErrorImageId);
                            }
                        }
    
                        @Override
                        public void onResponse(final ImageContainer response, boolean isImmediate) {
                            // If this was an immediate response that was delivered inside of a layout
                            // pass do not set the image immediately as it will trigger a requestLayout
                            // inside of a layout. Instead, defer setting the image by posting back to
                            // the main thread.
                            if (isImmediate && isInLayoutPass) {
                                post(new Runnable() {
                                    @Override
                                    public void run() {
                                        onResponse(response, false);
                                    }
                                });
                                return;
                            }
    
                            if (response.getBitmap() != null) {
                                setImageBitmap(response.getBitmap());
                            } else if (mDefaultImageId != 0) {
                                setImageResource(mDefaultImageId);
                            }
                        }
                    });
    
            // update the ImageContainer to be the new bitmap container.
            mImageContainer = newContainer;
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            loadImageIfNecessary(true);
        }
    
        @Override
        protected void onDetachedFromWindow() {
            if (mImageContainer != null) {
                // If the view was bound to an image request, cancel it and clear
                // out the image from the view.
                mImageContainer.cancelRequest();
                setImageBitmap(null);
                // also clear out the container so we can reload the image if necessary.
                mImageContainer = null;
            }
            super.onDetachedFromWindow();
        }
    
        @Override
        protected void drawableStateChanged() {
            super.drawableStateChanged();
            invalidate();
        }
    
        /**
         * In case the bitmap is manually changed, we make sure to
         * circle it on the next onDraw
         */
        @Override
        public void setImageBitmap(Bitmap bm) {
            mCircled = false;
            super.setImageBitmap(bm);
        }
        /**
         * In case the bitmap is manually changed, we make sure to
         * circle it on the next onDraw
         */
        @Override
        public void setImageResource(int resId) {
            mCircled = false;
            super.setImageResource(resId);
        }
    
        /**
         * In case the bitmap is manually changed, we make sure to
         * circle it on the next onDraw
         */
        @Override
        public void setImageDrawable(Drawable drawable) {
            mCircled = false;
            super.setImageDrawable(drawable);
        }
    
        /**
         * We want to make sure that the ImageView has the same height and width
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            Drawable drawable = getDrawable();
            if (drawable != null) {
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int diw = drawable.getIntrinsicWidth();
                if (diw > 0) {
                    int height = width * drawable.getIntrinsicHeight() / diw;
                    setMeasuredDimension(width, height);
                } else
                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            } else
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            //Let's circle the image
            if ( !mCircled && getDrawable() != null) {
                Drawable d = getDrawable();
                try {
                    //We use reflection here in case that the drawable isn't a
                    //BitmapDrawable but it contains a public getBitmap method.
                    Bitmap bitmap = (Bitmap) d.getClass().getMethod("getBitmap").invoke(d);
                    if(bitmap != null){
                        Bitmap circleBitmap = getCircleBitmap(bitmap);
                        setImageBitmap(circleBitmap);
                    }
                } catch (IllegalArgumentException e) {
                } catch (IllegalAccessException e) {
                } catch (InvocationTargetException e) {
                } catch (NoSuchMethodException e) {
                    //Seems like the current drawable is not a BitmapDrawable or
                    //that is doesn't have a public getBitmap() method.
                }
    
                //Mark as circled even if it failed, because if it fails once,
                //It will fail again.
                mCircled = true;
            }
            super.onDraw(canvas);
        }
    
        /**
         * Method used to circle a bitmap.
         *
         * @param bitmap The bitmap to circle
         * @return The circled bitmap
         */
        public static Bitmap getCircleBitmap(Bitmap bitmap) {
            int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
    
            Bitmap output = Bitmap.createBitmap(size,
                    size, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
    
            BitmapShader shader;
            shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
                    Shader.TileMode.CLAMP);
    
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setShader(shader);
    
            RectF rect = new RectF(0, 0 ,size,size);
            int radius = size/2;
            canvas.drawRoundRect(rect, radius,radius, paint);
            return output;
        }
    }
    

    【讨论】:

    • 虽然这可能会回答问题,但it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。
    • 是的,但只是基本部分。
    • 也需要包括它的使用方法?
    • 那很好,但是当前的代码很长并且包含很多大部分无关的支持代码;将其削减到关键部分会非常有帮助。
    【解决方案4】:

    您可以使用 CardView。

    <android.support.v7.widget.CardView 
        app:cardCornerRadius="@dimen/spacing_tiny">
    
        <com.android.volley.toolbox.NetworkImageView>
        ...
        />
    </android.support.v7.widget.CardView>
    

    【讨论】:

      【解决方案5】:

      我就是这样做的:

      • 在 volley 库中,复制名为“NetworkImageView”的类并将其命名为“NetworkImageViewCircle”。

        private void setAnimateImageBitmap(final Bitmap bitmap, boolean fadeIn) {
        
        final Bitmap bmp;
        
        bmp = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        BitmapShader shader = new BitmapShader(bitmap,
                BitmapShader.TileMode.CLAMP,
                BitmapShader.TileMode.CLAMP);
        
        float radius = Math.min(bitmap.getWidth(), bitmap.getHeight()) / 5;
        Canvas canvas = new Canvas(bmp);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(shader);
        
        RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
        canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
        .
        .
        .
        

      这对我来说是个窍门。希望有帮助。

      【讨论】:

        【解决方案6】:

        这对我有用

            <android.support.v7.widget.CardView
               android:id="@+id/container"
               android:layout_width="80dp"
               android:layout_height="80dp"
               app:cardCornerRadius="5dp"
               app:cardElevation="0dp" >
        
            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/thumb"
                android:layout_width="80dp"
                android:layout_height="80dp"/>
        
        </android.support.v7.widget.CardView>
        

        【讨论】:

          【解决方案7】:

          我可以在不扩展 NetworkImage 的情况下制作 circler NetworkImage

           <androidx.cardview.widget.CardView
                          android:id="@+id/myCardVi"
                          android:layout_width="188dp"
                          android:layout_height="188dp"
                          android:layout_centerHorizontal="true"
                          android:layout_gravity="center"
                          android:layout_marginTop="10dp"
                          android:alpha="0.95"
                          android:elevation="12dp"
                          android:innerRadius="0dp"
                          app:cardBackgroundColor="@color/white"
          
                          app:cardCornerRadius="94dp"
                          app:cardElevation="8dp">
          
                          <androidx.cardview.widget.CardView
                              android:id="@+id/myCardVie"
                              android:layout_width="match_parent"
                              android:layout_height="match_parent"
                              android:layout_centerHorizontal="true"
                              android:layout_margin="10dp"
                              android:alpha="0.95"
                              android:elevation="12dp"
                              android:innerRadius="0dp"
                              app:cardBackgroundColor="@color/cardview_dark_background"
          
                              app:cardCornerRadius="89dp"
                              app:cardElevation="8dp">
          
          
                              <com.android.volley.toolbox.NetworkImageView
                                  android:id="@+id/imageView"
                                  android:layout_width="178dp"
                                  android:layout_height="178dp"
                                  android:scaleType="fitXY"
          
                                  />
          
                          </androidx.cardview.widget.CardView>
                      </androidx.cardview.widget.CardView>
          

          【讨论】:

            【解决方案8】:

            凌空与圆角图像无关。

            您可以制作一个带有白色边框和透明内容的简单圆形。

            // res/drawable/circle.xml

              <shape xmlns:android="http://schemas.android.com/apk/res/android"
                     android:innerRadius="0dp"
                     android:shape="ring"
                     android:thicknessRatio="1.9"
                     android:useLevel="false" >
              <solid android:color="@android:color/transparent" />
            
                  <stroke
                       android:width="10dp"
                       android:color="@android:color/white" />
              </shape>
            

            然后制作一个可绘制的图层列表并将其作为网络图像视图的背景。

            // res/drawable/img.xml
            
            <?xml version="1.0" encoding="utf-8"?>
            <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
            
               <item android:drawable="@drawable/ic_launcher"/>
               <item android:drawable="@drawable/circle"/>
            
            </layer-list>
            

            并将其作为网络图像视图的背景。

             <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/networkImageView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:background="@drawable/img"
                android:src="@drawable/ic_launcher" />
            

            你会有类似的东西。

            【讨论】:

            • 你在img.xm中硬编码ic_launcher.png,我们需要对网络下载的图片进行四舍五入
            猜你喜欢
            • 2015-06-08
            • 2014-09-13
            • 1970-01-01
            • 2010-12-18
            • 1970-01-01
            • 2013-06-13
            • 2012-02-29
            • 2014-12-25
            • 1970-01-01
            相关资源
            最近更新 更多