Skip to content

Instantly share code, notes, and snippets.

@Grohden
Last active March 14, 2019 16:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Grohden/a847cca67c22925017cdd34f1255baa7 to your computer and use it in GitHub Desktop.
Save Grohden/a847cca67c22925017cdd34f1255baa7 to your computer and use it in GitHub Desktop.
Menu icon with count/badge - Android
<?xml version="1.0" encoding="utf-8"?>
<!-- This is the circle around the counter value -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#CC0001"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>
<item
android:id="@+id/actionFilter"
android:icon="@drawable/ic_funnel_white_24dp"
android:title="@string/filters"
app:showAsAction="always"
tools:ignore="AlwaysShowAction"
/>
</menu>
/* All the massive/repetitive/boring activity code above */
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
val filterMenu = menu.findItem(R.id.actionFilter)
/*
* Note: the view somehow manages to get ~3px more larger than a normal
* menu icon, i don't really now why the hell this happens and i could not
* fix that - i've spent like 5 hours just trying to make this shit work exacly like the
* default item.
*/
filterMenu.setIconWithCount(
requireContext(),
R.drawable.ic_funnel_white_24dp,
filterCount
)
}
/* All the massive/repetitive/boring activity code bellow */
package android.api.sucks
import android.content.Context
import android.graphics.drawable.BitmapDrawable
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import br.com.ngi.mnt.R
import kotlinx.android.synthetic.main.icon_with_count.view.*
/**
* Sets the icon with a counter badge on the top right corner
* if the count is not 0
*
* @param context the android god object
* @param iconRes the item icon id/res
* @param count the count value
*
*/
fun MenuItem.setIconWithCount(
context: Context,
@DrawableRes iconRes: Int,
count: Int
) {
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.icon_with_count, null)
AppCompatResources
.getDrawable(view.context, iconRes)
.let { view.counterIcon.setBackgroundDrawable(it) }
if (count == 0) {
view.count.gone()
} else {
view.count.text = "$count"
}
view.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
val bitmap = view.getBitmapFromView()
this.icon = BitmapDrawable(context.resources, bitmap)
}
/**
* Returns the view drawable (basically a screenshot of the view)
* the code is from this answer https://stackoverflow.com/a/52905682/4777865
*/
fun View.getBitmapFromView(): Bitmap {
val returnedBitmap = Bitmap.createBitmap(
measuredWidth,
measuredHeight,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(returnedBitmap)
val bgDrawable = this.background
if (bgDrawable != null) {
bgDrawable.draw(canvas)
} else {
canvas.drawColor(Color.TRANSPARENT)
}
draw(canvas)
return returnedBitmap
}
<?xml version="1.0" encoding="utf-8"?>
<!--
This is the view that will be rendered in the place of the 'pure icon'
Note: the layout preview is really distorted, but in the device it works
Note 2: the view somehow manages to get 3px~ more larger than a normal
Menu icon, i don't really know why the hell this happens and i could not
fix that.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/counterRoot"
android:layout_width="30dp"
android:layout_height="30dp"
android:clickable="true"
android:focusable="true"
tools:background="@android:color/black"
android:background="?attr/selectableItemBackground"
android:layout_gravity="center"
android:layout_marginBottom="2dp"
>
<ImageView
android:id="@+id/counterIcon"
android:layout_width="25dp"
android:layout_height="25dp"
tools:background="@drawable/ic_funnel_white_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="ContentDescription"
/>
<TextView
android:id="@+id/count"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginBottom="14dp"
android:layout_marginStart="16dp"
android:background="@drawable/circular_red_shape"
tools:text="1"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="10sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="SmallSp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment