BadgeDrawable 是否不适用于 FrameLayout 中的视图,例如按钮、图像、文本视图等?

Does BadgeDrawable not work for views within a FrameLayout such as buttons, images, textviews etc.?

我的主 activity 中有这个功能,它不显示徽章:

private fun setFindShiftBadge(state: HomeState) {
        val findShiftsBadge = BadgeDrawable.create(this)
        home_framelayout.foreground = findShiftsBadge
        findShiftsBadge.badgeGravity = BadgeDrawable.TOP_END
        findShiftsBadge.backgroundColor = resources.getColor(R.color.colorWhite)
        findShiftsBadge.badgeTextColor = resources.getColor(R.color.colorPrimary)
        findShiftsBadge.number = state.availableShifts.size
 }

在同一个 activity 中,我有这个显示徽章的函数:

private fun setMyPostedShiftBadge(state: HomeState) {
    val userShiftsBadge: BadgeDrawable =
        bottom_navigation_view.getOrCreateBadge(R.id.bottom_navigation_my_posted_shifts_text)
    userShiftsBadge.number = state.userShifts.size
    userShiftsBadge.backgroundColor = resources.getColor(R.color.colorPrimary)
} 

现在我明白第二个函数起作用了,因为徽章是在 BottomNavigationView 中设置的。具有讽刺意味的是,BottomNavigationView 扩展了 FrameLayout。在 Android 文档中: 使用 attachBadgeDrawable(BadgeDrawable, View, FrameLayout) 将 BadgeDrawable 作为 ViewOverlay 添加到所需的锚视图。 使用 updateBadgeCoordinates(View, ViewGroup).

基于锚点视图更新 BadgeDrawable BadgeDrawable 的坐标(中心和边界)

他们说要使用这段代码,For API 18+ (APIs supported by ViewOverlay) 我在第一个不起作用的函数中使用了它:

 BadgeDrawable badgeDrawable = BadgeDrawable.create(context);
 BadgeUtils.attachBadgeDrawable(badgeDrawable, anchor, null);

我也试过这个,但也没用。我知道有一些解决方法,例如:

  1. 创建一个可绘制对象然后将其设置到您想要的视图上
  2. 在该可绘制对象中放置一个 TextView,然后用您想要的数字更新它
  3. 当有任何数字时切换可绘制对象的可见性。

我在implementation 'com.google.android.material:material:1.2.0-alpha04'

这对我来说似乎很脏,因为我知道有更好的方法来做到这一点。我就是想不通。我错过了什么?这可能吗?您是如何在不必编写变通方法的情况下做到这一点的?谢谢你的时间!期待从您的问题和答案中学习!!祝你有美好的一天!

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

为了设置边界,让我们为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)
}

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

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>