Android中如何将Bitmap适配自定义圆角矩形并保持宽高比?
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

