0

I can't seem to figure out how can I make an image (such as ImageView) a circle image, inside an app widget. I mean crop it in the form of a circle, like .clipShape(Circle()) in SwiftUI.

I tried some solutions but they won't work in widgets:

  • ShapeableImageView breaks the widget
  • Androidx library is not allowed in widget

Any other solutions?

Updated

I have tried doing it programatically from Kotlin, converting the solution from here:

class AppWidgetProvider : HomeWidgetProvider() {
        override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
        appWidgetIds.forEach { widgetId ->
            val view = RemoteViews(context.packageName, R.layout.widget_layout)
            val pendingIntent = HomeWidgetLaunchIntent.getActivity(
                context,
                MainActivity::class.java,
                Uri.parse("https://example.com"))
            view.setOnClickPendingIntent(R.id.widgetRoot, pendingIntent)
            val logoBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.app_icon)
            view.setImageViewBitmap(R.id.smarthutsLogo, getCroppedBitmap(logoBitmap))
            appWidgetManager.updateAppWidget(widgetId, view)
        }
    }

    @Throws(Exception::class)
    fun getCroppedBitmap(bitmap: Bitmap): Bitmap {
        val output: Bitmap =
            Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(output)
        val color = -0xbdbdbe
        val paint = Paint()
        val rect = Rect(0, 0, bitmap.width, bitmap.height)
        paint.isAntiAlias = true
        canvas.drawARGB(0, 0, 0, 0)
        paint.color = color
        canvas.drawCircle(
            (bitmap.width / 2).toFloat(),
            (bitmap.height / 2).toFloat(),
            (bitmap.width / 2).toFloat(),
            paint
        )
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, rect, rect, paint)
        return output
    }
}

HomeWidgetProvider is from a Flutter plugin, you can find the code for it here.

What happens is that the the image despite being being cropped as a circle it's shown with a white square background.

adi
  • 417
  • 4
  • 25
  • Did you tried https://stackoverflow.com/questions/32912664/android-circular-imageview-in-app-widget this ? – Bincy Baby Feb 01 '23 at 08:46
  • Hi @BincyBaby I have tried it, but nothing happens. Updated the answer to show how I tried it. – adi Feb 01 '23 at 10:30
  • "But nothing happened" -- we do not know what that means, and we do not have enough code to see how you are sending this cropped image to the `AppWidgetManager`. If you remove the call to `getCroppedBitmap()` in your last line of your second code snippet, and you do not see the *uncropped* bitmap, then your problem is not with the cropping but with how you are trying to update your app widget UI. – CommonsWare Feb 01 '23 at 12:23
  • Indeed, "nothing happened" was an error on my side, sorry, because it still showed as square. I've tested with another image and it seems the image is cropped into a circle and put on a white-square. I have updated the post to include the entire class. – adi Feb 01 '23 at 13:36
  • Ok, I figured it out. The square white background was because I had android:background="@android:color/white" attribute to the ImageView tag. – adi Feb 01 '23 at 14:01
  • your issue resolved ? – Bincy Baby Feb 01 '23 at 15:54
  • Yes, it's resolved. Had to dig up how to actually use it, but in the end is done. Thanks – adi Feb 01 '23 at 15:58

1 Answers1

0

From this issue, using Android Studio's code converter, I managed to make a solution in Kotlin:

@Throws(Exception::class)
    fun getCroppedBitmap(bitmap: Bitmap): Bitmap {
        val output: Bitmap =
            Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(output)
        val paint = Paint()
        val rect = Rect(0, 0, bitmap.width, bitmap.height)
        paint.isAntiAlias = true
        canvas.drawCircle(
            (bitmap.width / 2).toFloat(),
            (bitmap.height / 2).toFloat(),
            (bitmap.width / 2).toFloat(),
            paint
        )
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, rect, rect, paint)
        return output
    }

The newly created function can be used inside the widget's onUpdate method as follows:

val view = RemoteViews(context.packageName, R.layout.widget_layout)
val logoBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.app_icon)
view.setImageViewBitmap(R.id.imageView, getCroppedBitmap(logoBitmap))

Be careful not have android:background="@android:color/white" added to your ImageView. If you need to add a background color, add it when creating the bitmap.

adi
  • 417
  • 4
  • 25