如何制作带圆角图片的Material You风格Widget(RemoteView限制场景)
Got it, let's tackle this problem head-on—since RemoteViews lock us out of using modern components like ShapeableImageView, we need to work with the limited, supported tools to get that Google Photos-style rounded corner Material You widget. Here are two reliable, API 24+ compatible approaches:
Approach 1: Use RoundedBitmapDrawable (Simplest & AndroidX-Native)
RoundedBitmapDrawable is fully supported by RemoteViews and lets us create rounded corners directly from a bitmap, plus we can tie it to your existing appWidgetRadius dimension for consistency.
Step-by-Step Implementation:
- First, ensure you have AndroidX dependencies in your module-level
build.gradle:
implementation "androidx.core:core-ktx:1.12.0" implementation "androidx.appcompat:appcompat:1.6.1"
- In your
AppWidgetProviderclass, update the widget with the rounded drawable:
override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { appWidgetIds.forEach { appWidgetId -> val remoteViews = RemoteViews(context.packageName, R.layout.widget) // Load your target image (replace with your actual loading logic) val originalBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.MY_IMAGE) // Fetch your defined corner radius from dimens.xml val cornerRadius = context.resources.getDimension(R.dimen.rounded_corners) // Create and configure the rounded drawable val roundedDrawable = RoundedBitmapDrawableFactory.create(context.resources, originalBitmap) roundedDrawable.cornerRadius = cornerRadius roundedDrawable.isCircular = false roundedDrawable.setAntiAlias(true) // Attach the drawable to your ImageView remoteViews.setImageViewDrawable(R.id.widget_image, roundedDrawable) // Push updates to the widget appWidgetManager.updateAppWidget(appWidgetId, remoteViews) } }
Approach 2: Manually Crop Bitmap with Canvas (Full Control)
If you need more flexibility (like non-uniform corners, though Material You uses uniform ones), you can manually generate a rounded bitmap using Canvas and Paint. This works seamlessly with RemoteViews too.
Step-by-Step Implementation:
First, add this helper function to your AppWidgetProvider or a utility class:
private fun getRoundedCornerBitmap(bitmap: Bitmap, cornerRadius: Float): Bitmap { val outputBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) val canvas = Canvas(outputBitmap) val paint = Paint().apply { isAntiAlias = true xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) } val rect = Rect(0, 0, bitmap.width, bitmap.height) val rectF = RectF(rect) // Draw the rounded background mask canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint) // Draw the original bitmap over the mask canvas.drawBitmap(bitmap, rect, rect, paint) return outputBitmap }
Then use it in your onUpdate method:
override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { appWidgetIds.forEach { appWidgetId -> val remoteViews = RemoteViews(context.packageName, R.layout.widget) val originalBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.MY_IMAGE) val cornerRadius = context.resources.getDimension(R.dimen.rounded_corners) val roundedBitmap = getRoundedCornerBitmap(originalBitmap, cornerRadius) remoteViews.setImageViewBitmap(R.id.widget_image, roundedBitmap) appWidgetManager.updateAppWidget(appWidgetId, remoteViews) } }
Bonus: Match Material You Widget Background
To make the widget fully align with Material You styling, apply the same corner radius to your layout's background:
- Create
res/drawable/widget_background.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="?android:attr/colorBackground" /> <corners android:radius="@dimen/rounded_corners" /> </shape>
- Update your
widget.xmlLinearLayout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/widget_background" android:theme="@style/widget_theme"> <!-- Your ImageView here --> </LinearLayout>
Quick Notes:
- Remote Image Loading: If you're using remote images instead of drawables, use libraries like Glide (with
AppWidgetTarget) or Coil (withRemoteViewsTarget)—they handle bitmap resizing and rounding safely for widgets. - Performance: Resize bitmaps to match your widget's actual size before applying rounding to avoid memory overhead. Use
Bitmap.createScaledBitmapfor this.
内容的提问来源于stack exchange,提问作者Vreny

