1

I am developing an android app using:

  • Jetpack Lifecycle (ViewModel)
  • Jetpack Navigation
  • Coil (Image Loader)

I am trying to customize the BottomNavigationMenu.

But one thing is very hard...

enter image description here

The last tab is the User's profile Image with Border.

If the user's profile image background color is white, then the ui is weird. So I should show the border.

class MainActivity {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initBottomNav(binding.bottomNav)
        vm.initProfileBottomIcon()
    }

    private fun initBottomNav(bottomNav: BottomNavigationView) {
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        bottomNav.setupWithNavController(navHostFragment.navController)
        bottomNav.itemIconTintList = null

        vm.profileImgUrl.observe(this) { url ->
            bottomNav.menu.findItem(R.id.profileFragment).load(this, url) {
                transformations(CircleCropTransformation())
            }
        }
    }
}

This code draws the profile image on the BottomNavigationMenu. But not draw the border.

When I googling, there is no support for CircleCrop with Border on Coil (even Glide).

So I tried the below code, But it doesn't work well..

vm.profileImg.observe(this) { imgBitmap ->
    val layerBorder = ResourcesCompat.getDrawable(resources, R.drawable.oval_trans_border1_red, null)
    val layerIcon = BitmapDrawable(Resources.getSystem(), imgBitmap)
    val layerDrawable = LayerDrawable(arrayOf(layerIcon, layerBorder))

    val bottomNavProfile = bottomNav.menu.findItem(R.id.profileFragment)
    val request = ImageRequest.Builder(this)
        .data(layerDrawable)
        .target {
            bottomNavProfile.icon = it
        }
        .apply {
            transformations(CircleCropTransformation())
        }
        .build()
    imageLoader.enqueue(request)
}

Somebody help me please?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
yoonhok
  • 2,575
  • 2
  • 30
  • 58
  • 1
    When you load `profileImg` you can use a Transformation to add the border . It will give you a Drawable/Bitmap . have you tried this way ? If there is no transformation available you can create one . Its should not be hard you just have to modify `Circular Transformation` class when talking about Glide . something Like [This](https://stackoverflow.com/a/53606048/4168607). – ADM Jan 13 '22 at 08:45

1 Answers1

2

You can write your own Transformation with border like this:

class BorderedCircleCropTransformation(
    private val borderSize: Float = 0f,
    @ColorInt private val borderColor: Int = Color.BLUE
) : Transformation {

    override fun key(): String = BorderedCircleCropTransformation::class.java.name

    override suspend fun transform(pool: BitmapPool, input: Bitmap, size: Size): Bitmap {
        val borderOffset = (borderSize * 2).toInt()
        val halfWidth = input.width / 2
        val halfHeight = input.height / 2
        val circleRadius = Math.min(halfWidth, halfHeight).toFloat()
        val newBitmap = Bitmap.createBitmap(
            input.width + borderOffset,
            input.height + borderOffset,
            Bitmap.Config.ARGB_8888
        )

        // Center coordinates of the image
        val centerX = halfWidth + borderSize
        val centerY = halfHeight + borderSize

        val paint = Paint()
        val canvas = Canvas(newBitmap).apply {
            // Set transparent initial area
            drawARGB(0, 0, 0, 0)
        }

        // Draw the transparent initial area
        paint.isAntiAlias = true
        paint.style = Paint.Style.FILL
        canvas.drawCircle(centerX, centerY, circleRadius, paint)

        // Draw the image
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(input, borderSize, borderSize, paint)

        // Draw the createBitmapWithBorder
        paint.xfermode = null
        paint.style = Paint.Style.STROKE
        paint.color = borderColor
        paint.strokeWidth = borderSize
        canvas.drawCircle(centerX, centerY, circleRadius, paint)
        return newBitmap
    }

    override fun equals(other: Any?) = other is BorderedCircleCropTransformation

    override fun hashCode() = javaClass.hashCode()

    override fun toString() = "BorderedCircleCropTransformation()"

    private companion object {
        val XFERMODE = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
    }
}

internal val Bitmap.safeConfig: Bitmap.Config
    get() = config ?: Bitmap.Config.ARGB_8888

then pass it as a transformation to coil and it will draw what you want. I use this code for drawing border.

Mobin Yardim
  • 695
  • 7
  • 17