How to create a partially-rounded-corners-rectangular drawable with center-crop and without creating new bitmap?

南笙酒味 提交于 2019-11-30 20:38:54

The SMART way is to use the PorterDuff blending mode. It's really simple and slick to create any fancy shading, blending, "crop" effect. you can find a lot of good tutorial about PorterDuff. here a good one.

I always use this library to achieve what you are looking for. you can round any corner you want and also add stroke.

https://github.com/vinc3m1/RoundedImageView

You can use it or see it's source codes just for inspiration.

EDIT

there is no need to use Image View and make bitmap or drawable yourself and show it in Image View. Just replace Image View with Rounded Image View and it will handle everything for you without any extra work in code ! here is sample :

<com.makeramen.roundedimageview.RoundedImageView
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/imageView1"
    android:scaleType="centerCrop"
    app:riv_corner_radius="8dp"
    app:riv_border_width="2dp"
    app:riv_border_color="#333333"
    app:riv_oval="false" />

In code, just pass any image resource to it or use any Image Loader with it.

RoundedImageView myRoundedImage=(RoundedImageView)findViewById(R.id.imageView1);
myRoundedImage.setImageResource(R.drawable.MY_DRAWABLE);
// OR
ImageLoader.getInstance().displayImage(YOUR_IMAGE_URL, myRoundedImage);

if you want to just make specific corners rounded try this:

 <com.makeramen.roundedimageview.RoundedImageView
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/imageView1"
    android:scaleType="centerCrop"
    app:riv_corner_radius_top_right="8dp"
    app:riv_corner_radius_bottom_right="8dp"
    app:riv_border_width="2dp"
    app:riv_border_color="#333333"
    app:riv_oval="false" />

Well, you can create a new .xml drawable named my_background and paste this code below:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid android:color="#00000000"/>
    <corners
        android:bottomLeftRadius="12dp"
        android:bottomRightRadius="12dp"
        android:topLeftRadius="12dp"
        android:topRightRadius="12dp" />
    <stroke
        android:width="1dp"
        android:color="#000000"
        />
</shape>

Then, you set your ImageButton's, ImageView's background to your new drawable, like this:

android:background="@drawable/my_background"
android:scaleType="centerCrop"

or programatically:

myView.setBackground(R.drawable.my_background);

Hope it helps!

EDIT:

To programmatically create a similar drawable, you can use it:

GradientDrawable shape = new GradientDrawable();
    shape.setShape(GradientDrawable.RECTANGLE);
    shape.setCornerRadii(new float[] { 8, 8, 8, 8, 0, 0, 0, 0 });
    shape.setColor(Color.TRANSPARENT);
    shape.setStroke(3, Color.BLACK);
    v.setBackgroundDrawable(shape);

Ok, here's my try. The only gotcha is that "int corners" is meant to be a set of flags. Such as 0b1111 where each 1 represents a corner to be rounded, and 0 is the opposite. The order is TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT.

example usage first, formatted for readability:

((ImageView) findViewById(R.id.imageView)).setImageDrawable(
    new RoundedRectDrawable(
        getResources(),
        bitmap,
        (float) .15,
        0b1101,
        8,
        Color.YELLOW
    )
);

code:

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.SystemClock;

/**
 * Created by mliu on 4/15/16.
 */
public class RoundedRectDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
private final float outlineBorderRadius;
private final int w;
private final int h;
private final int corners;
private final int border;
private final int bordercolor;

public RoundedRectDrawable(final Resources resources, final Bitmap bitmap, float borderRadiusSeed, int corners, int borderPX, int borderColor) {
    super(resources, bitmap);
    bitmapShader = new BitmapShader(getBitmap(),
            BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
    final Bitmap b = getBitmap();
    p = getPaint();
    p.setAntiAlias(true);
    p.setShader(bitmapShader);
    w = b.getWidth();
    h = b.getHeight();
    rect = new RectF(0,0,w,h);
    borderRadius = borderRadiusSeed * Math.min(w, h);
    border = borderPX;
    this.corners = corners;
    this.bordercolor = borderColor;
    outlineBorderRadius = borderRadiusSeed * Math.min(w+border,h+border);
}

@Override
public void draw(final Canvas canvas) {
    if ((corners&0b1111)==0){
        if (border>0) {
            Paint border = new Paint();
            border.setColor(bordercolor);
            canvas.drawRect(rect, border);
        }
        canvas.drawRect(rect.left + border, rect.top + border, rect.width() - border, rect.height() - border, p);
    } else {
        if (border >0) {
            Paint border = new Paint();
            border.setColor(bordercolor);
            canvas.drawRoundRect(rect, outlineBorderRadius, outlineBorderRadius, border);

            if ((corners & 0b1000) == 0) {
                //top left
                canvas.drawRect(rect.left, rect.top, rect.width() / 2, rect.height() / 2, border);
            }
            if ((corners & 0b0100) == 0) {
                //top right
                canvas.drawRect(rect.width() / 2, rect.top, rect.width(), rect.height() / 2, border);
            }
            if ((corners & 0b0010) == 0) {
                //bottom left
                canvas.drawRect(rect.left, rect.height() / 2, rect.width() / 2, rect.height(), border);
            }
            if ((corners & 0b0001) == 0) {
                //bottom right
                canvas.drawRect(rect.width() / 2, rect.height() / 2, rect.width(), rect.height(), border);
            }
        }
        canvas.drawRoundRect(new RectF(rect.left + border, rect.top + border, rect.width() - border, rect.height() - border), borderRadius, borderRadius, p);
        if ((corners & 0b1000) == 0) {
            //top left
            canvas.drawRect(rect.left + border, rect.top + border, rect.width() / 2, rect.height() / 2, p);
        }
        if ((corners & 0b0100) == 0) {
            //top right
            canvas.drawRect(rect.width() / 2, rect.top + border, rect.width() - border, rect.height() / 2, p);
        }
        if ((corners & 0b0010) == 0) {
            //bottom left
            canvas.drawRect(rect.left + border, rect.height() / 2, rect.width() / 2, rect.height() - border, p);
        }
        if ((corners & 0b0001) == 0) {
            //bottom right
            canvas.drawRect(rect.width() / 2, rect.height() / 2, rect.width() - border, rect.height() - border, p);
        }
    }
}

}

So, this handles the outline first, if needed, then the bitmap. It marks the canvas up with a rounded rect first, then "squares out" each corner you don't want to round. Seems highly inefficient, and probably is, but average case run time before minimal optimizations (corners = 0b0000, 10 canvas.draw calls) takes ~ 200us on a S7. And, that time is SUPER inconsistent based on phone usage. I've gotten as low as 80us and as high as 1.5ms.

NOTES/WARNING: I am BAD at this. This is not optimal. There's probably better answers already here on SO. The subject matter is just a bit uncommon and difficult to search up. I was originally not going to post this, but at time of writing this is still not marked answered, and the library OP did not wish to use due to problems with their Drawable actually use a very similar approach as my terrible solution. So, now I'm less embarrassed to share this. Additionally, though what I posted today was 95% written yesterday, I know I got some of this code from a tutorial or a SO post, but I can't remember who to attribute cause I didn't end up using it in my project. Apologies whoever you are.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!