You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何将Bitmap适配自定义圆角矩形并保持宽高比?

How to Implement Custom Non-Standard Rounded Rect ImageView with Aspect Ratio Preservation

Got it, let's tackle this non-standard rounded rectangle ImageView issue you're facing. Since RoundedBitmapDrawable only handles circles or uniform rounded corners, we need a custom approach here—here's how to do it step by step, including support for dynamic image updates:


1. Build a Custom Drawable for Non-Uniform Rounded Corners

We'll create a custom BitmapDrawable that uses Canvas.clipPath to define our exact rounded shape. This lets us set different radii for each corner, matching your attachment's style.

public class CustomRoundRectDrawable extends BitmapDrawable {
    private final Path clipPath;
    private final RectF bitmapBounds;
    private final float[] cornerRadii;

    // Constructor takes corner radii (in dp) for each corner: top-left, top-right, bottom-right, bottom-left
    public CustomRoundRectDrawable(Resources res, Bitmap bitmap, float tlRadius, float trRadius, float brRadius, float blRadius) {
        super(res, bitmap);
        clipPath = new Path();
        bitmapBounds = new RectF();
        
        // Convert dp to pixels for proper scaling across devices
        float density = res.getDisplayMetrics().density;
        cornerRadii = new float[]{
                tlRadius * density, tlRadius * density,
                trRadius * density, trRadius * density,
                brRadius * density, brRadius * density,
                blRadius * density, blRadius * density
        };
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        bitmapBounds.set(bounds);
        clipPath.reset();
        // Add our custom rounded rectangle path to the clip
        clipPath.addRoundRect(bitmapBounds, cornerRadii, Path.Direction.CW);
    }

    @Override
    public void draw(Canvas canvas) {
        // Clip the canvas so only the rounded area is drawn
        canvas.clipPath(clipPath);
        super.draw(canvas);
    }
}

2. Keep Your Aspect Ratio Scaling Logic

Your existing scaleBitmapAndKeepRation method is perfect for preserving the image's original aspect ratio while fitting it to the ImageView. Keep using that:

private Bitmap scaleBitmapAndKeepRation(Bitmap bitmap, int targetWidth, int targetHeight) {
    int originalWidth = bitmap.getWidth();
    int originalHeight = bitmap.getHeight();
    
    float scaleFactor = Math.min(
            (float) targetWidth / originalWidth,
            (float) targetHeight / originalHeight
    );

    Matrix scaleMatrix = new Matrix();
    scaleMatrix.postScale(scaleFactor, scaleFactor);

    return Bitmap.createBitmap(bitmap, 0, 0, originalWidth, originalHeight, scaleMatrix, true);
}

3. Replace the Circular Logic with Custom Rounded Rect

Update your image loading code to use our new custom drawable instead of RoundedBitmapDrawable. Adjust the corner radii values to match your attachment's style:

// After picking image from gallery
Bitmap FixBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);

// Get ImageView's target dimensions (convert dp to pixels)
int targetWidth = (int) getResources().getDimension(R.dimen._137sdp);
int targetHeight = (int) getResources().getDimension(R.dimen._150sdp);

// Scale image while keeping aspect ratio
Bitmap scaledBitmap = scaleBitmapAndKeepRation(FixBitmap, targetWidth, targetHeight);

// Create custom drawable with your desired corner radii (example: 20dp top-left, 0dp top-right, 20dp bottom-right, 0dp bottom-left)
CustomRoundRectDrawable customDrawable = new CustomRoundRectDrawable(
        getResources(), 
        scaledBitmap, 
        20f, 0f, 20f, 0f
);

// Set the drawable to your ImageView
p_avatar.setImageDrawable(customDrawable);

4. Support Dynamic Image Updates

For swapping images dynamically (when the user picks a new photo), just repeat the above steps: fetch the new Bitmap, scale it, create a new CustomRoundRectDrawable, and call p_avatar.setImageDrawable() with the new drawable. It works exactly like your current circular image update flow—just swap the drawable creation part.

5. Alternative: XML Shape Overlay (Less Reliable for Aspect Ratio)

If your rounded shape is fixed, you could use a shape drawable as the ImageView's foreground, but this can cause image stretching if your scaleType isn't set perfectly. Here's how that looks, but I recommend the custom Drawable approach for better control:

Create drawable/custom_round_rect_overlay.xml:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@android:color/transparent" />
    <corners
        android:topLeftRadius="20dp"
        android:topRightRadius="0dp"
        android:bottomRightRadius="20dp"
        android:bottomLeftRadius="0dp" />
</shape>

Update your ImageView XML:

<ImageView
    android:id="@+id/avatar"
    android:layout_width="137dp"
    android:layout_height="150dp"
    android:clickable="true"
    android:paddingTop="@dimen/_10sdp"
    android:paddingBottom="@dimen/_10sdp"
    android:foreground="@drawable/custom_round_rect_overlay"
    android:scaleType="centerCrop" />

That should get you exactly the custom rounded shape you need, while keeping your image's aspect ratio intact and supporting dynamic image swaps.

内容的提问来源于stack exchange,提问作者Marcus Barnet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:09:51