Skip to content

Commit

Permalink
[MDCBadge] Allow MDCBadgeView to take on a dot badge style.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 692247823
  • Loading branch information
loading-google authored and material-automation committed Nov 1, 2024
1 parent 2d71b8a commit 8eb898d
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
20 changes: 20 additions & 0 deletions components/Badges/src/Appearance/MDCBadgeAppearance.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#import "MDCMinimumOS.h" // IWYU pragma: keep

NS_ASSUME_NONNULL_BEGIN

/** An object for customizing the appearance of a badge. */
__attribute__((objc_subclassing_restricted))
@interface MDCBadgeAppearance : NSObject<NSCopying>
Expand All @@ -38,6 +40,22 @@ __attribute__((objc_subclassing_restricted))
/** The font that will be used to display the value. */
@property(nonatomic, strong, nullable) UIFont *font;

/**
The radius of the filled portion of the dot badge. Only used if `dotBadgeEnabled` is YES.
The width and height of the dot badge's frame will be equal to
(dotBadgeInnerRadius + borderWidth) * 2.
*/
@property(nonatomic) CGFloat dotBadgeInnerRadius;

/**
Whether the badge should be a dot badge.
Dot badges do not display any text. Enabling this flag will cause the badge to ignore any text
set on the badge.
*/
@property(nonatomic) BOOL dotBadgeEnabled;

/**
The color of the border surrounding the badge.
Expand All @@ -55,3 +73,5 @@ __attribute__((objc_subclassing_restricted))
@property(nonatomic) CGFloat borderWidth;

@end

NS_ASSUME_NONNULL_END
6 changes: 6 additions & 0 deletions components/Badges/src/Appearance/MDCBadgeAppearance.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#import "MDCBadgeAppearance.h"

NS_ASSUME_NONNULL_BEGIN

@implementation MDCBadgeAppearance

- (nonnull instancetype)init {
Expand All @@ -10,6 +12,8 @@ - (nonnull instancetype)init {

- (nonnull id)copyWithZone:(nullable __unused NSZone *)zone {
MDCBadgeAppearance *config = [[MDCBadgeAppearance alloc] init];
config.dotBadgeEnabled = self.dotBadgeEnabled;
config.dotBadgeInnerRadius = self.dotBadgeInnerRadius;
config.backgroundColor = self.backgroundColor;
config.textColor = self.textColor;
config.font = self.font;
Expand All @@ -19,3 +23,5 @@ - (nonnull id)copyWithZone:(nullable __unused NSZone *)zone {
}

@end

NS_ASSUME_NONNULL_END
50 changes: 48 additions & 2 deletions components/Badges/src/MDCBadgeView.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
// TODO(featherless): Remove the dependency on MDCPalette.
#import "MDCPalettes.h"

NS_ASSUME_NONNULL_BEGIN

static const CGFloat kBadgeFontSize = 8;
static const CGFloat kBadgeYPadding = 2;
static const CGFloat kMinDiameter = 9;
Expand Down Expand Up @@ -47,6 +49,8 @@
@implementation MDCBadgeView {
UIColor *_Nullable _borderColor;
UILabel *_Nonnull _label;
CGFloat _dotBadgeInnerRadius;
BOOL _dotBadgeEnabled;
}

@synthesize appearance = _appearance;
Expand All @@ -63,6 +67,7 @@ - (nonnull instancetype)initWithFrame:(CGRect)frame {
_label = [[UILabel alloc] initWithFrame:self.bounds];
_label.textAlignment = NSTextAlignmentCenter;
_label.isAccessibilityElement = NO;
_label.hidden = _appearance.dotBadgeEnabled;
[self addSubview:_label];
}
return self;
Expand All @@ -80,6 +85,18 @@ - (CGFloat)badgeXPaddingForRadius:(CGFloat)radius {
- (void)layoutSubviews {
[super layoutSubviews];

if (_appearance.dotBadgeEnabled) {
[self layoutDotBadge];
} else {
[self layoutTextBadge];
}
}

- (void)layoutDotBadge {
self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2;
}

- (void)layoutTextBadge {
CGFloat badgeRadius = CGRectGetHeight(self.bounds) / 2;
CGRect availableContentRect = CGRectStandardize(
CGRectInset(self.bounds, [self badgeXPaddingForRadius:badgeRadius], kBadgeYPadding));
Expand All @@ -91,6 +108,19 @@ - (void)layoutSubviews {
}

- (CGSize)sizeThatFits:(CGSize)size {
if (_appearance.dotBadgeEnabled) {
return [self sizeThatFitsDotBadge:size];
} else {
return [self sizeThatFitsTextBadge:size];
}
}

- (CGSize)sizeThatFitsDotBadge:(CGSize)size {
const CGFloat squareDimension = (_dotBadgeInnerRadius + self.layer.borderWidth) * 2;
return CGSizeMake(squareDimension, squareDimension);
}

- (CGSize)sizeThatFitsTextBadge:(CGSize)size {
if (_label.text == nil) {
return CGSizeZero;
}
Expand Down Expand Up @@ -128,8 +158,10 @@ - (void)didMoveToWindow {
- (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection {
[super traitCollectionDidChange:previousTraitCollection];

[self updateFont];
[self updateBorderColor];
if (!_appearance.dotBadgeEnabled) {
[self updateFont];
[self updateBorderColor];
}
}

- (void)updateFont {
Expand All @@ -152,6 +184,18 @@ - (void)applyAppearance {
_label.textColor = _appearance.textColor;
if (![_label.font isEqual:_appearance.font]) {
[self updateFont];
intrinsicSizeAffected = !_appearance.dotBadgeEnabled;
}

// Layout
if (_dotBadgeInnerRadius != _appearance.dotBadgeInnerRadius) {
_dotBadgeInnerRadius = _appearance.dotBadgeInnerRadius;
intrinsicSizeAffected = intrinsicSizeAffected || _appearance.dotBadgeEnabled;
}

if (_dotBadgeEnabled != _appearance.dotBadgeEnabled) {
_dotBadgeEnabled = _appearance.dotBadgeEnabled;
_label.hidden = _appearance.dotBadgeEnabled;
intrinsicSizeAffected = YES;
}

Expand Down Expand Up @@ -203,3 +247,5 @@ - (nonnull MDCBadgeAppearance *)appearance {
}

@end

NS_ASSUME_NONNULL_END

0 comments on commit 8eb898d

Please sign in to comment.