【Android】BadgeDrawable을 ImageView에서 어떻게 든 사용해 보는 방법

소개



통지의 건수 표시등에 사용할 수 있는 BadgeDrawable ( Badge - Material Design )입니다만, 바삭바삭하게 사용할 수 있어 매우 편리합니다.

↓처럼 쓰면 ...
bottomNavigationView.getOrCreateBadge(R.id.navigation_home).apply {
    number = 10
}

Home 탭에 Badge가 표시됩니다.


단, 현재(material-components-android v1.2.1)라면 BottomNavigationView 인가 TabLayout예를 들어 BottomNavigationView 에서 사용하고 있는 Badge와 같은 외형의 것을 다른 곳에서도 사용하고 싶다고 하는 경우에 모여 버립니다.

이 기사에서는 BadgeDrawableImageView 에서 어떻게든 사용해 보는 방법을 소개하고 싶습니다.

↓ "This is home Fragment"의 오른쪽에 있는 Badge가 BadgeDrawableImageView로 표시해 본 것입니다.


※ Material Components는 com.google.android.material:material:1.2.1 에서 확인하고 있습니다.
※ Badge에 관해서는 htps : // 이 m/미안해/있어 ms/75795f5314d852d74485 의 기사가 매우 참고가 되었습니다.

재밌게 사용해 보지만 ...


BadgeDrawable 에는 create(Context) 라는 그것 같은 메소드가 있습니다만, 그것을 사용해 BadgeDrawable 의 인스턴스를 생성해, ImageView 에 세트 해 봐도 아무것도 표시되지 않습니다.
val badgeImageView: ImageView = ...
val badgeDrawable = BadgeDrawable.create(context).apply {
    number = 10
}
badgeImageView.setImageDrawable(badgeDrawable)

↓ Badge가 표시되지 않는다.


표시되지 않는 이유는 create(Context) 한 것만으로는 Drawable 의 크기(bounds)가 설정되어 있지 않기 때문입니다.

BottomNavigationView의 getOrCreateBadge(int)를 쫓아보기



그래서, BottomNavigationView 의 Badge를 표시하는 메소드인 getOrCreateBadge(int) 를 쫓아 보면,
BadgeUtilsattachBadgeDrawable 라는 메소드가 불려 그 안에서 더
setBadgeDrawableBounds 이라는 메소드가 불리는 것을 알 수 있습니다.

setBadgeDrawableBounds 라는 메소드가 사이즈의 계산을 하고 있는 곳이 됩니다.
BadgeUtils@RestrictTo(Scope.LIBRARY) 어노테이션이 붙어 있기 때문에, 그대로 사용하면 Lint 경고가 나옵니다. 다행히 메소드의 내용의 처리는 복잡하지 않으므로, 그것을 참고로 하여 사이즈의 계산을 실현시키면 좋을 것 같습니다.

BadgeUtils.java
  public static void setBadgeDrawableBounds(
      @NonNull BadgeDrawable badgeDrawable,
      @NonNull View anchor,
      @NonNull FrameLayout compatBadgeParent) {
    Rect badgeBounds = new Rect();
    View badgeParent = USE_COMPAT_PARENT ? compatBadgeParent : anchor;
    badgeParent.getDrawingRect(badgeBounds);
    badgeDrawable.setBounds(badgeBounds);
    badgeDrawable.updateBadgeCoordinates(anchor, compatBadgeParent);
  }

ImageView에 표시



세세한 workaround를 더하면서, BadgeDrawable
val badgeImageView: ImageView = ...
val badgeDrawable = BadgeDrawable.create(context).apply {
    number = 10
    // (1)
    val badgeBounds = Rect()
    badgeImageView.getDrawingRect(badgeBounds)
    this.bounds = badgeBounds
    this.updateBadgeCoordinates(badgeImageView, null)
    // (2)
    this.horizontalOffset = (-6).dp
    this.verticalOffset = 8.dp
}
badgeImageView.setImageDrawable(badgeDrawable)

(1)


ImageView 의 내부에서 하고 있는 처리를 똑같이 실행하고 있습니다.setBadgeDrawableBounds 에서는 SDK 버전에 의한 분기가 있습니다만 생략하고 있습니다. setBadgeDrawableBounds 또한 null입니다. Badge의 앵커에 compatBadgeParent를 지정하는 것은 위화감이 있습니다만, 이것으로 움직였기 때문에 문제는 없는 것 같습니다.

(2)



workaround감 가득합니다만, 묘화의 위치가 어긋나 버리는 것 같았으므로 offset를 조정하고 있습니다.


offset 없음
offset 있음






badgeImageViewImageView 에 착색한 모습.

기타



Badge를 표시하는 경우, 드로잉이 빠지지 않도록 부모 레이아웃에 clipping을 지정해야합니다.
android:clipChildren="false"
android:clipToPadding="false"

표시됨



이상의 공정으로, 어떻게든 backgroundBadgeDrawable 로 사용할 수 있었습니다.ImageView 그러면 애니메이션 등도 간단하게 적용할 수 있으므로, 좋은 느낌입니다.


요약


ImageViewBadgeDrawable 로 어떻게든 사용해 보는 방법을 소개했습니다.
workaround등도 있어도, ImageView 에 Badge를 표시할 수 있어 애니메이션이나 세세한 위치 조정등도 가능하게 되므로, 사용의 폭이 퍼지는 것은 아닐까 생각합니다.
ImageView 에 대해 어드바이스등 있으면, 코멘트 받을 수 있으면 기쁩니다.

참고

좋은 웹페이지 즐겨찾기