ImageView in circular through xml

前端 未结 27 1002
死守一世寂寞
死守一世寂寞 2020-11-22 10:35

I\'d Like to make any image from my ImageView to be circular with a border.

I searched but couldn\'t find any useful information (anything that I tried

相关标签:
27条回答
  • 2020-11-22 10:51

    Try this.

    public class RoundedImageView extends android.support.v7.widget.AppCompatImageView {
    
        private int borderWidth = 4;
        private int viewWidth;
        private int viewHeight;
        private Bitmap image;
        private Paint paint;
        private Paint paintBorder;
        private BitmapShader shader;
    
        public RoundedImageView(Context context)
        {
            super(context);
            setup();
        }
    
        public RoundedImageView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            setup();
        }
    
        public RoundedImageView(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
            setup();
        }
    
        private void setup()
        {
            paint = new Paint();
            paint.setAntiAlias(true);
    
            paintBorder = new Paint();
            setBorderColor(Color.WHITE);
            paintBorder.setAntiAlias(true);
            this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
    
            paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.WHITE);
        }
    
        public void setBorderWidth(int borderWidth)
        {
            this.borderWidth = borderWidth;
            this.invalidate();
        }
    
        public void setBorderColor(int borderColor)
        {
            if (paintBorder != null)
                paintBorder.setColor(borderColor);
    
            this.invalidate();
        }
    
        private void loadBitmap()
        {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
    
            if (bitmapDrawable != null)
                image = bitmapDrawable.getBitmap();
        }
    
        @SuppressLint("DrawAllocation")
        @Override
        public void onDraw(Canvas canvas)
        {
            loadBitmap();
    
            if (image != null)
            {
                shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                paint.setShader(shader);
                int circleCenter = viewWidth / 2;
                canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter + borderWidth - 4.0f, paintBorder);
                canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter - 4.0f, paint);
            }
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int width = measureWidth(widthMeasureSpec);
            int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
    
            viewWidth = width - (borderWidth * 2);
            viewHeight = height - (borderWidth * 2);
    
            setMeasuredDimension(width, height);
        }
    
        private int measureWidth(int measureSpec)
        {
            int result = 0;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
    
            if (specMode == MeasureSpec.EXACTLY)
            {
                result = specSize;
            }
            else
            {
                // Measure the text
                result = viewWidth;
            }
    
            return result;
        }
    
        private int measureHeight(int measureSpecHeight, int measureSpecWidth)
        {
            int result = 0;
            int specMode = MeasureSpec.getMode(measureSpecHeight);
            int specSize = MeasureSpec.getSize(measureSpecHeight);
    
            if (specMode == MeasureSpec.EXACTLY)
            {
                result = specSize;
            }
            else
            {
                result = viewHeight;
            }
    
            return (result + 2);
         }
     }
    

    and use this ImageView in layout like:

    <com.app.Demo.RoundedImageView
         android:id="@+id/iv_profileImage"
         android:layout_width="70dp"
         android:layout_height="70dp"
         android:layout_centerHorizontal="true"
        />
    
    0 讨论(0)
  • 2020-11-22 10:52

    @Jyotman Singh, answer is very good (for solid backgrounds), so I would like to enhance it by sharing vector drawable that can be re-colored for your needs, also it is convenient since vector one-piece shape is well scalable.

    This is the rectangle-circle shape (@drawable/shape_round_profile_pic):

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:viewportWidth="284"
        android:viewportHeight="284"
        android:width="284dp"
        android:height="284dp">
        <path
            android:pathData="M0 142L0 0l142 0 142 0 0 142 0 142 -142 0 -142 0zm165 137.34231c26.06742 -4.1212 52.67405 -17.543 72.66855 -36.65787 11.82805 -11.30768 20.55487 -22.85153 27.7633 -36.72531C290.23789 158.21592 285.62874 101.14121 253.48951 58.078079 217.58149 9.9651706 154.68849 -10.125717 98.348685 8.5190299 48.695824 24.95084 12.527764 67.047123 3.437787 118.98655 1.4806194 130.16966 1.511302 152.96723 3.4990422 164.5 12.168375 214.79902 47.646316 256.70775 96 273.76783c21.72002 7.66322 44.26673 9.48476 69 5.57448z"
            android:fillColor="#ffffff" /> // you can change frame color
    </vector>
    

    Usage is the same:

    <FrameLayout
            android:layout_width="70dp"
            android:layout_height="70dp">
    
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/YOUR_PICTURE" />
    
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/shape_round_profile_pic"/>
    
        </FrameLayout>
    
    0 讨论(0)
  • 2020-11-22 10:52

    I have a simple solution. Create a new Image asset by right clicking your package name and selecting New->Image asset. Enter name (any name) and path (location of image in your system). Then click Next and Finish. If you enter name of image as 'img', a round image with the name 'img_round' is created automatically in mipmap folder.

    Then, do this :

    <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:src="@mipmap/img_round"/>
    

    Your preview may still show a rectangular image. But if you run the app on your device, it will be round.

    0 讨论(0)
  • 2020-11-22 10:53

    You can make a simple circle with white border and transparent content with shape.

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

    Then make a layerlist drawable and put it as background to your imageview.

    // 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/circle"/>    
        <item android:drawable="@drawable/ic_launcher"/>
    
    </layer-list>
    

    and put it as background to your imageview.

       <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/img"/>
    

    You'll have something like that.

    enter image description here

    0 讨论(0)
  • 2020-11-22 10:53

    With the help of glide library and RoundedBitmapDrawableFactory class it's easy to achieve. You may need to create circular placeholder image.

    Glide V4:

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

    Glide V3:

        Glide.with(context)
            .load(imgUrl)
            .asBitmap()
            .placeholder(R.drawable.placeholder)
            .error(R.drawable.placeholder)
            .into(new BitmapImageViewTarget(imgProfilePicture) {
                @Override
                protected void setResource(Bitmap resource) {
                    RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(),
                            Bitmap.createScaledBitmap(resource, 50, 50, false));
                    drawable.setCircular(true);
                    imgProfilePicture.setImageDrawable(drawable);
                }
            });
    

    For Picasso RoundedTransformation, this is a really great solution that gives an additional option of rounding image at either top or bottom edge.

    0 讨论(0)
  • 2020-11-22 10:53

    Another idea is to use clipToOutline property of an ImageView.

    Here is an example layout:

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <!-- Simple view to draw borders for an image,
             borders will be rounded because of the oval-shaped background. -->
        <View
            android:id="@+id/v_border"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="@drawable/shape_border"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <!-- Image itself: fits the border view, 
             a margin serves as a border width;
             the key point here - is a background shape which will clip the view to its forms. -->
        <ImageView
            android:id="@+id/iv_image"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_margin="4dp"
            android:background="@drawable/shape_oval"
            android:src="@mipmap/ic_launcher"
            app:layout_constraintBottom_toBottomOf="@+id/v_border"
            app:layout_constraintEnd_toEndOf="@+id/v_border"
            app:layout_constraintStart_toStartOf="@+id/v_border"
            app:layout_constraintTop_toTopOf="@+id/v_border" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    And here are our shape_border drawable:

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

    And shape_oval drawable:

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

    The only thing you should do in the code - is to enable clipToOutline property:

    binding.ivImage.clipToOutline = true
    

    And of course you can avoid even this line of the code with some BindingAdapter.

    0 讨论(0)
提交回复
热议问题