6

I'm using arimorty/floatingsearchview library for searchbar and it is working fine but now I want to a notification icon with a red circle/badge without count, but cannot find a way to make it.

in activity:

<com.arlib.floatingsearchview.FloatingSearchView
        android:id="@+id/floating_search_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:floatingSearch_searchHint="Search..."
        app:floatingSearch_suggestionsListAnimDuration="250"
        app:floatingSearch_showSearchKey="false"
        app:floatingSearch_leftActionMode="showHamburger"
        app:floatingSearch_menu="@menu/searchbar_sidemenu"
        app:floatingSearch_close_search_on_keyboard_dismiss="true"
        android:paddingEnd="10dp"
        android:paddingStart="10dp"
        android:paddingTop="10dp"/>

menu code:

<?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">
    <item android:id="@+id/action_notification"
        android:title="Notification"
        app:showAsAction="ifRoom"
        android:icon="@drawable/ic_notifications_none_black_24dp"/>
</menu>

I tried other answer but none of them worked for me.

current view screenshot

expected view screenshot

I will explain/clarify or share java code if needed.

[Update]

I tried to implement this answer and other answer.

searched in GitHub repo and found this but did not understand.

  • 1
    @tynn thanks for reply, please see my updated question. –  Jul 28 '20 at 18:03
  • do you want red circle to be always present or enabled/disabled dynamically? – Rinat Diushenov Jul 29 '20 at 08:40
  • 1
    @Rinat yes, I want to red circle to show or hide dynamically. –  Jul 29 '20 at 10:03
  • Can you try this : ( (FloatingSearchView)findViewById(R.id.floating_search_view) ).getCurrentMenuItems().get(0).setIcon(R.drawable.iconWithBadge); – Rinat Diushenov Jul 29 '20 at 13:45
  • 1
    @Rinat Thanks you response, I tried but it is raising a NullPointerException. `Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference` –  Jul 30 '20 at 19:00
  • 1
    I see only one solution then: download arimorty/floatingsearchview library, add it to your project as amodule, modify it by add public function to modify the menu icon. – Rinat Diushenov Jul 30 '20 at 19:34
  • How did you _try_ to show and hide the red circle dynamically? – Bruno Bieri Aug 04 '20 at 09:14

2 Answers2

0

change your search icon use this:

myIcon.setDrawable(setBadgeCount(context, R.drawable.ic_shopping_cart_primary, 1));

use this class to change drawable with badgedDrawable:

public static Drawable setBadgeCount(Context context, int res, int badgeCount) {
    LayerDrawable icon = (LayerDrawable) ContextCompat.getDrawable(context, R.drawable.ic_badge_drawable);
    Drawable mainIcon = ContextCompat.getDrawable(context, res);
    BadgeDrawable badge = new BadgeDrawable(context);
    badge.setCount(String.valueOf(badgeCount));
    assert icon != null;
    icon.mutate();
    icon.setDrawableByLayerId(R.id.ic_badge, badge);
    icon.setDrawableByLayerId(R.id.ic_main_icon, mainIcon);
    return icon;
}

create this class:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import androidx.annotation.NonNull;

public class BadgeDrawable extends Drawable {

    private Paint mBadgePaint;
    private Paint mBadgePaint1;
    private Paint mTextPaint;
    private Rect mTxtRect = new Rect();

    private String mCount = "";
    private boolean mWillDraw = false;


    public BadgeDrawable(Context context) {
        float mTextSize = dpToPx(context); //text size
        mBadgePaint = new Paint();
        mBadgePaint.setColor(Color.RED);
        mBadgePaint.setAntiAlias(true);
        mBadgePaint.setStyle(Paint.Style.FILL);
        mBadgePaint1 = new Paint();
        mBadgePaint1.setColor(Color.parseColor("#EEEEEE"));
        mBadgePaint1.setAntiAlias(true);
        mBadgePaint1.setStyle(Paint.Style.FILL);

        mTextPaint = new Paint();
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTypeface(Typeface.DEFAULT);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
    }

    private float dpToPx(Context context) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (float) 8, context.getResources().getDisplayMetrics());
    }


    @Override
    public void draw(@NonNull Canvas canvas) {
        if (!mWillDraw) {
            return;
        }
        Rect bounds = getBounds();
        float width = bounds.right - bounds.left;
//        float height = bounds.bottom - bounds.top;
        // Position the badge in the top-right quadrant of the icon.

        /*Using Math.max rather than Math.min */
        //        float radius = ((Math.max(width, height) / 2)) / 2;
        float radius = width * 0.15f;
        float centerX = (width - radius - 1) +10;
        float centerY = radius -5;
        if(mCount.length() <= 2){
            // Draw badge circle.
            canvas.drawCircle(centerX, centerY, radius+9, mBadgePaint1);
            canvas.drawCircle(centerX, centerY, radius+7, mBadgePaint);
        }
        else {
            canvas.drawCircle(centerX, centerY, radius+10, mBadgePaint1);
            canvas.drawCircle(centerX, centerY, radius+8, mBadgePaint);
        }
        // Draw badge count text inside the circle.
        mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
        float textHeight = mTxtRect.bottom - mTxtRect.top;
        float textY = centerY + (textHeight / 2f);
        if(mCount.length() > 2)
            canvas.drawText("99+", centerX, textY, mTextPaint);
        else
            canvas.drawText(mCount, centerX, textY, mTextPaint);
    }

    /*
     Sets the count (i.e notifications) to display.
      */
    public void setCount(String count) {
        mCount = count;
        // Only draw a badge if there are notifications.
        mWillDraw = !count.equalsIgnoreCase("0");
        invalidateSelf();
    }

    @Override
    public void setAlpha(int alpha) {
        // do nothing
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        // do nothing
    }

    @Override
    public int getOpacity() {
        return PixelFormat.UNKNOWN;
    }
}

in setCount change mWillDraw = !count.equalsIgnoreCase("0"); to true if you wanna show without number

res:

ic_badge_drawable.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/ic_main_icon"
        android:drawable="@drawable/ic_shopping_cart_primary"
        android:gravity="center" />


    <!-- set a place holder Drawable so android:drawable isn't null -->
    <item android:id="@+id/ic_badge"
        android:drawable="@drawable/ic_shopping_cart_primary" />
</layer-list>

replace ic_shopping_cart_primary with any drawable, that's not uset, just for default

Review codes and change setCount to pass " " (space)

Shahriyar Aghajani
  • 431
  • 1
  • 6
  • 22
0

Thanks to @Rinat for his comment

Here is details answer.

  1. Download arimorty/floatingsearchview and import it as module (detailed answer for import) if you are using java you can just import library folder from downloaded.

  2. After importing open MenuView file src->main->java->com.arlib.floatingsearchview->util->view->MenuView.java in this file find ImageView action = createActionView(); change action to global field

create a new method in MenuView

public void chngNotificationIcon(int ResID){
 action.setImageResource(ResID);
}
  1. Open FloatingSearchView.java file and create this method as well

    public void chngNotificationIcon(int ResID){ mMenuView.chngNotificationIcon(ResID); }

  2. Create a new drawbale in you main project for notification with red circle and name it notification_withdot.xml

now you can set any icon using

floatingSearchViewObject.chngNotificationIcon(R.drawable.notification_withdot);

let me know if you face any error.

Mahmood Sanjrani
  • 108
  • 3
  • 19