徽章可绘制不显示

Badge Drawable not showing

为什么BadgeDrawable没有显示在任何地方?我正在尝试添加 MaterialCardViewMaterialButton 等。它没有显示。有人知道如何解决这个问题吗?或者有相同的库来替换它?

代码如下:

val badgeDrawable = BadgeDrawable.create(holder.itemView.context)
badgeDrawable.number = 10
badgeDrawable.badgeGravity = BadgeDrawable.TOP_END
badgeDrawable.backgroundColor = holder.itemView.context.getColor(R.color.colorAccent)
holder.itemView.home_cardview.overlay.add(badgeDrawable)
badgeDrawable.updateBadgeCoordinates(holder.itemView.home_cardview, null)

这个方法也行不通:

BadgeUtils.attachBadgeDrawable(badgeDrawable, anchor, null);

顺便说一下,在新版本中 compatBadgeParent 是必填字段

验证您使用的版本,我正在使用:

com.google.android.material:material: 1.1.0-beta01

然后试试这个:

bottomNavigationView.getOrCreateBadge(R.id.menu_item_notifications).apply {
            backgroundColor = resources.getColor(R.color.red)
            badgeTextColor = resources.getColor(R.color.white)
            maxCharacterCount = 3
            number = 10 //should be change
            isVisible = true
        }

我遇到了同样的问题。 这可能是 Badge 库中的错误。 这是工作:

        badgeDrawable = BadgeDrawable.create(frameLayoutContainer.getContext());
        frameLayoutContainer.setForeground(badgeDrawable);
        frameLayoutContainer.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
            //
            badgeDrawable.updateBadgeCoordinates(frameLayoutContainer, frameLayoutContainer);
        });

frameLayoutContainer 是一个将 BadgeDrawable 设置为其前景的 FrameLayout。

这是 posted by @0X0nosugar on my 所以请去看看他的回答并给他点个赞。链接放在上面,谢谢!

BottomNavigationView.getOrCreateBadge() 不仅将 BadgeDrawable 指定为前景 Drawable,而且还设置了 drawable 边界。如果没有这一步,它们会停留在 (0,0,0,0),所以没有什么可画的。

为了设置bounds,给BadgeDrawable

引入一个扩展函数
/**
 * Inspired by BadgeUtils in com.google.android.material library
 *
 * Sets the bounds of a BadgeDrawable 
 */
private fun BadgeDrawable.setBoundsFor(@NonNull anchor: View, @NonNull parent: FrameLayout){
    val rect = Rect()
    parent.getDrawingRect(rect)
    this.setBounds(rect)
    this.updateBadgeCoordinates(anchor, parent)
}

将此函数与 FrameLayout 的 BadgeDrawable 一起使用:

private fun setFindShiftBadge(state: HomeState) {
    val findShiftsBadge = BadgeDrawable.create(this)
    // configure the badge drawable
    findShiftsBadge.badgeGravity = BadgeDrawable.TOP_END
    findShiftsBadge.backgroundColor = resources.getColor(R.color.colorWhite)
    findShiftsBadge.badgeTextColor = resources.getColor(R.color.colorPrimary)
    findShiftsBadge.number = state.availableShifts.size
    // set bounds inside which it will be drawn
    findShiftsBadge.setBoundsFor(btn_badge, home_framelayout)
    // assign as foreground drawable
    home_framelayout.foreground = findShiftsBadge
}

    BadgeDrawable badgeDrawable = BadgeDrawable.create(this);
    badgeDrawable.setNumber(15);

    FrameLayout frameLayout = findViewById(R.id.framelayout);

    ImageView imageView = findViewById(R.id.iv_center);

    //core code
    frameLayout.setForeground(badgeDrawable);
    frameLayout.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {


        //either of the following two lines of code  work
        //badgeDrawable.updateBadgeCoordinates(imageView, frameLayout);
        BadgeUtils.attachBadgeDrawable(badgeDrawable, imageView, frameLayout);
    });





    <FrameLayout
        android:id="@+id/framelayout"
        android:layout_width="150dp"
        android:layout_height="150dp">

        <ImageView
            android:layout_gravity="center"
            android:id="@+id/iv_center"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:scaleType="fitXY"
            android:src="@drawable/ic_beard" />
    </FrameLayout>

您可以使用以下布局将 BadgeDrawable 应用于 MaterialCardViewMaterialButton

<FrameLayout
    android:id="@+id/layout"
    android:clipChildren="false"
    android:clipToPadding="false"
    ..>

        <com.google.android.material.card.MaterialCardView
            android:id="@+id/card"
            .../>

</FrameLayout>

那就用方法BadgeUtils.attachBadgeDrawable.

例如 CardView:

    MaterialCardView cardview = findViewById(R.id.card);
    cardview.setClipToOutline(false);  //Important with a CardView

    cardview.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            BadgeDrawable badgeDrawable = BadgeDrawable.create(MainActivity.this);
            badgeDrawable.setNumber(15);
            BadgeUtils.attachBadgeDrawable(badgeDrawable, cardview, findViewById(R.id.layout));

            cardview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

对于Button:

<FrameLayout
    android:id="@+id/layout"
    android:clipChildren="false"
    android:clipToPadding="false">

  <com.google.android.material.button.MaterialButton
      android:id="@+id/button"
      ../>

</FrameLayout>

然后是类似的代码:

    button.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            BadgeDrawable badgeDrawable = BadgeDrawable.create(MainActivity.this);
            badgeDrawable.setNumber(7);
            badgeDrawable.setBackgroundColor(......);
            badgeDrawable.setVerticalOffset(20);
            badgeDrawable.setHorizontalOffset(15);

            BadgeUtils.attachBadgeDrawable(badgeDrawable, button, findViewById(R.id.layout));

            button.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

您可以在 Kotlin 中使用不带 FrameLayout 的以下函数:

视图 是您要放置通知徽章的组件!

@SuppressLint("UnsafeExperimentalUsageError")
    private fun initBadge(view : View, nbrNotification : Int) {

        if(nbrNotification == 0) return // Don't show the badge

        view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {

            override fun onGlobalLayout() {

                BadgeDrawable.create(requireContext()).apply {
                    number = nbrNotification
                    verticalOffset = 70
                    horizontalOffset = 70
                    //badgeDrawable.setBackgroundColor() #to change the background color
                    BadgeUtils.attachBadgeDrawable(this, view)
                }

                view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })
    }

这里我实现了 BadgeDrawable using BadgeUtils 和 xml 样式来在 Button 上添加徽章。

private fun setBadgeCount(count: Int) {
        BadgeDrawable.createFromResource(this, R.xml.badge_style).apply {
            number = count
            BadgeUtils.attachBadgeDrawable(this, binding.buttonContact)
        }
    }

badge_style.xml:

<badge xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/Widget.MaterialComponents.Badge"
    app:backgroundColor="#FF0000"
    app:badgeTextColor="#FFFFFF"
    app:horizontalOffset="6dp"
    app:maxCharacterCount="2"
    app:verticalOffset="8dp" />

输出:

参考:

  1. https://material.io/develop/android/supporting/badge
  2. https://developer.android.com/reference/com/google/android/material/badge/package-summary