Skip to content

Commit b51ecb4

Browse files
committed
Added Liquid Glass variant to the background style
1 parent 21519b8 commit b51ecb4

File tree

1 file changed

+77
-34
lines changed

1 file changed

+77
-34
lines changed

TORoundedButton/TORoundedButton.m

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,18 @@
2727

2828
// --------------------------------------------------------------------
2929

30-
static inline BOOL TO_ROUNDED_BUTTON_FLOAT_IS_ZERO(CGFloat value) {
30+
static inline BOOL TORoundedButtonFloatIsZero(CGFloat value) {
3131
return (value > -FLT_EPSILON) && (value < FLT_EPSILON);
3232
}
3333

34-
static inline BOOL TO_ROUNDED_BUTTON_FLOATS_MATCH(CGFloat firstValue, CGFloat secondValue) {
34+
static inline BOOL TORoundedButtonFloatsMatch(CGFloat firstValue, CGFloat secondValue) {
3535
return fabs(firstValue - secondValue) > FLT_EPSILON;
3636
}
3737

38+
static inline BOOL TORoundedButtonIsDynamicBackground(TORoundedButtonBackgroundStyle backgroundStyle) {
39+
return backgroundStyle != TORoundedButtonBackgroundStyleSolid;
40+
}
41+
3842
// --------------------------------------------------------------------
3943

4044
@implementation TORoundedButton {
@@ -50,6 +54,9 @@ @implementation TORoundedButton {
5054

5155
/** A background view that displays the rounded box behind the button text. */
5256
UIView *_backgroundView;
57+
58+
/** Manage an internal reference to the corner configuration so we can apply it to different backgrounds. */
59+
UICornerConfiguration *_cornerConfiguration API_AVAILABLE(ios(26.0));
5360
}
5461

5562
#pragma mark - View Creation -
@@ -102,13 +109,20 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
102109
_tappedTextAlpha = (_tappedTextAlpha > FLT_EPSILON) ?: 1.0f;
103110
_tapAnimationDuration = (_tapAnimationDuration > FLT_EPSILON) ?: 0.4f;
104111
_tappedButtonScale = (_tappedButtonScale > FLT_EPSILON) ?: 0.97f;
105-
_tappedTintColorBrightnessOffset = !TO_ROUNDED_BUTTON_FLOAT_IS_ZERO(_tappedTintColorBrightnessOffset) ?: -0.15f;
112+
_tappedTintColorBrightnessOffset = !TORoundedButtonFloatIsZero(_tappedTintColorBrightnessOffset) ?: -0.15f;
106113
_contentInset = (UIEdgeInsets){15.0, 15.0, 15.0, 15.0};
107114
_blurStyle = UIBlurEffectStyleDark;
108115
#ifdef __IPHONE_13_0
109116
if (@available(iOS 13.0, *)) { _blurStyle = UIBlurEffectStyleSystemThinMaterialDark; }
110117
#endif
111118

119+
// Set the corner radius depending on system version
120+
if (@available(iOS 26.0, *)) {
121+
_cornerConfiguration = [UICornerConfiguration capsuleConfiguration];
122+
} else {
123+
_cornerRadius = (_cornerRadius > FLT_EPSILON) ?: 12.0f;
124+
}
125+
112126
// Set the tapped tint color if we've set to dynamically calculate it
113127
[self _updateTappedTintColorForTintColor];
114128

@@ -117,11 +131,10 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
117131
_containerView.backgroundColor = [UIColor clearColor];
118132
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
119133
_containerView.userInteractionEnabled = NO;
120-
_containerView.clipsToBounds = YES;
121134
[self addSubview:_containerView];
122135

123136
// Create the image view which will show the button background
124-
_backgroundView = [self _makeBackgroundViewWithBlur:_isTranslucent];
137+
_backgroundView = [self _makeBackgroundViewWithStyle:_backgroundStyle];
125138
[_containerView addSubview:_backgroundView];
126139

127140
// The foreground content view
@@ -132,13 +145,6 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
132145
[self addTarget:self action:@selector(_didTouchUpInside) forControlEvents:UIControlEventTouchUpInside];
133146
[self addTarget:self action:@selector(_didDragOutside) forControlEvents:UIControlEventTouchDragExit|UIControlEventTouchCancel];
134147
[self addTarget:self action:@selector(_didDragInside) forControlEvents:UIControlEventTouchDragEnter];
135-
136-
// Set the corner radius depending on app version
137-
if (@available(iOS 26.0, *)) {
138-
self.cornerConfiguration = [UICornerConfiguration capsuleConfiguration];
139-
} else {
140-
_cornerRadius = (_cornerRadius > FLT_EPSILON) ?: 12.0f;
141-
}
142148
}
143149

144150
- (void)_makeTitleLabelIfNeeded TOROUNDEDBUTTON_OBJC_DIRECT {
@@ -160,18 +166,36 @@ - (void)_makeTitleLabelIfNeeded TOROUNDEDBUTTON_OBJC_DIRECT {
160166
[_contentView addSubview:_titleLabel];
161167
}
162168

163-
- (UIView *)_makeBackgroundViewWithBlur:(BOOL)withBlur TOROUNDEDBUTTON_OBJC_DIRECT {
169+
- (UIView *)_makeBackgroundViewWithStyle:(TORoundedButtonBackgroundStyle)style TOROUNDEDBUTTON_OBJC_DIRECT {
164170
UIView *backgroundView = nil;
165-
if (withBlur) {
166-
UIBlurEffect *const blurEffect = [UIBlurEffect effectWithStyle:_blurStyle];
167-
backgroundView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
168-
backgroundView.clipsToBounds = YES;
171+
if (TORoundedButtonIsDynamicBackground(style)) {
172+
// Create a glass or blur style based on the associated style
173+
UIVisualEffect *effect = nil;
174+
if (@available(iOS 26.0, *)) {
175+
if (style == TORoundedButtonBackgroundStyleGlass) {
176+
UIGlassEffect *const glassEffect = [UIGlassEffect effectWithStyle:_glassStyle];
177+
glassEffect.interactive = YES;
178+
glassEffect.tintColor = self.tintColor;
179+
effect = glassEffect;
180+
}
181+
}
182+
if (effect == nil) {
183+
UIBlurEffect *const blurEffect = [UIBlurEffect effectWithStyle:_blurStyle];
184+
effect = blurEffect;
185+
}
186+
backgroundView = [[UIVisualEffectView alloc] initWithEffect:effect];
169187
} else {
170188
backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
171189
backgroundView.backgroundColor = self.tintColor;
172190
}
173191
backgroundView.frame = self.bounds;
174192
backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
193+
if (@available(iOS 26.0, *)) {
194+
backgroundView.cornerConfiguration = _cornerConfiguration;
195+
} else {
196+
backgroundView.clipsToBounds = TORoundedButtonIsDynamicBackground(style);
197+
backgroundView.layer.cornerRadius = _cornerRadius;
198+
}
175199
#ifdef __IPHONE_13_0
176200
if (@available(iOS 13.0, *)) { backgroundView.layer.cornerCurve = kCACornerCurveContinuous; }
177201
#endif
@@ -244,7 +268,7 @@ - (CGSize)sizeThatFits:(CGSize)size {
244268

245269
- (void)tintColorDidChange {
246270
[super tintColorDidChange];
247-
if (_isTranslucent) { return; }
271+
if (TORoundedButtonIsDynamicBackground(_backgroundStyle)) { return; }
248272
_titleLabel.backgroundColor = [self _labelBackgroundColor];
249273
_backgroundView.backgroundColor = self.tintColor;
250274
[self setNeedsLayout];
@@ -257,7 +281,7 @@ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
257281
}
258282

259283
- (void)_updateTappedTintColorForTintColor TOROUNDEDBUTTON_OBJC_DIRECT {
260-
if (TO_ROUNDED_BUTTON_FLOAT_IS_ZERO(_tappedTintColorBrightnessOffset)) {
284+
if (TORoundedButtonFloatIsZero(_tappedTintColorBrightnessOffset)) {
261285
return;
262286
}
263287

@@ -272,7 +296,7 @@ - (void)_updateTappedTintColorForTintColor TOROUNDEDBUTTON_OBJC_DIRECT {
272296

273297
- (UIColor *)_labelBackgroundColor TOROUNDEDBUTTON_OBJC_DIRECT {
274298
// Always return clear if tapped
275-
if (_isTapped || _isTranslucent) { return [UIColor clearColor]; }
299+
if (_isTapped || TORoundedButtonIsDynamicBackground(_backgroundStyle)) { return [UIColor clearColor]; }
276300

277301
// Return clear if the tint color isn't opaque
278302
const BOOL isClear = CGColorGetAlpha(self.tintColor.CGColor) < (1.0f - FLT_EPSILON);
@@ -327,7 +351,7 @@ - (void)_didDragInside {
327351
#pragma mark - Animation -
328352

329353
- (void)_setBackgroundColorTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DIRECT {
330-
if (!_tappedTintColor || _isTranslucent) { return; }
354+
if (!_tappedTintColor || TORoundedButtonIsDynamicBackground(_backgroundStyle)) { return; }
331355

332356
// Toggle the background color of the title label
333357
void (^updateTitleOpacity)(void) = ^{
@@ -489,7 +513,9 @@ - (void)setTextPointSize:(CGFloat)textPointSize {
489513
- (void)setTintColor:(UIColor *)tintColor {
490514
[super setTintColor:tintColor];
491515
[self _updateTappedTintColorForTintColor];
492-
_backgroundView.backgroundColor = tintColor;
516+
if (!TORoundedButtonIsDynamicBackground(_backgroundStyle)) {
517+
_backgroundView.backgroundColor = tintColor;
518+
}
493519
_titleLabel.backgroundColor = [self _labelBackgroundColor];
494520
[self setNeedsLayout];
495521
}
@@ -502,7 +528,7 @@ - (void)setTappedTintColor:(UIColor *)tappedTintColor {
502528
}
503529

504530
- (void)setTappedTintColorBrightnessOffset:(CGFloat)tappedTintColorBrightnessOffset {
505-
if (TO_ROUNDED_BUTTON_FLOATS_MATCH(_tappedTintColorBrightnessOffset,
531+
if (TORoundedButtonFloatsMatch(_tappedTintColorBrightnessOffset,
506532
tappedTintColorBrightnessOffset)) { return; }
507533

508534
_tappedTintColorBrightnessOffset = tappedTintColorBrightnessOffset;
@@ -520,29 +546,30 @@ - (void)setCornerRadius:(CGFloat)cornerRadius {
520546

521547
if (@available(iOS 26.0, *)) {
522548
UICornerRadius *const radius = [UICornerRadius fixedRadius:_cornerRadius];
523-
_backgroundView.cornerConfiguration = [UICornerConfiguration configurationWithUniformRadius:radius];
549+
_cornerConfiguration = [UICornerConfiguration configurationWithUniformRadius:radius];
550+
_backgroundView.cornerConfiguration = _cornerConfiguration;
524551
} else {
525552
_backgroundView.layer.cornerRadius = _cornerRadius;
553+
_backgroundView.layer.masksToBounds = TORoundedButtonIsDynamicBackground(_backgroundStyle);
526554
}
527555
[self setNeedsLayout];
528556
}
529557

530558
- (void)setCornerConfiguration:(UICornerConfiguration *)cornerConfiguration {
531-
_backgroundView.cornerConfiguration = cornerConfiguration;
559+
if (_cornerConfiguration == cornerConfiguration) { return; }
560+
_cornerConfiguration = cornerConfiguration;
561+
_backgroundView.cornerConfiguration = _cornerConfiguration;
532562
}
533563

534564
- (UICornerConfiguration *)cornerConfiguration {
535-
return _backgroundView.cornerConfiguration;
565+
return _cornerConfiguration;
536566
}
537567

538-
- (void)setIsTranslucent:(BOOL)isTranslucent {
539-
if (_isTranslucent == isTranslucent) {
540-
return;
541-
}
542-
543-
_isTranslucent = isTranslucent;
568+
- (void)setBackgroundStyle:(TORoundedButtonBackgroundStyle)backgroundStyle {
569+
if (_backgroundStyle == backgroundStyle) { return; }
570+
_backgroundStyle = backgroundStyle;
544571
[_backgroundView removeFromSuperview];
545-
_backgroundView = [self _makeBackgroundViewWithBlur:_isTranslucent];
572+
_backgroundView = [self _makeBackgroundViewWithStyle:_backgroundStyle];
546573
[_containerView insertSubview:_backgroundView atIndex:0];
547574
_titleLabel.backgroundColor = [self _labelBackgroundColor];
548575
[self setNeedsLayout];
@@ -554,14 +581,30 @@ - (void)setBlurStyle:(UIBlurEffectStyle)blurStyle {
554581
}
555582

556583
_blurStyle = blurStyle;
557-
if (!_isTranslucent || ![_backgroundView isKindOfClass:[UIVisualEffectView class]]) {
584+
if (!TORoundedButtonIsDynamicBackground(_backgroundStyle) || ![_backgroundView isKindOfClass:[UIVisualEffectView class]]) {
558585
return;
559586
}
560587

561588
UIVisualEffectView *const blurView = (UIVisualEffectView *)_backgroundView;
562589
[blurView setEffect:[UIBlurEffect effectWithStyle:_blurStyle]];
563590
}
564591

592+
- (void)setGlassStyle:(UIGlassEffectStyle)glassStyle {
593+
if (_glassStyle == glassStyle) { return; }
594+
_glassStyle = glassStyle;
595+
596+
if (!TORoundedButtonIsDynamicBackground(_backgroundStyle) || ![_backgroundView isKindOfClass:[UIVisualEffectView class]]) {
597+
return;
598+
}
599+
600+
UIGlassEffect *const glassEffect = [UIGlassEffect effectWithStyle:_glassStyle];
601+
glassEffect.tintColor = self.tintColor;
602+
glassEffect.interactive = YES;
603+
604+
UIVisualEffectView *const effectView = (UIVisualEffectView *)_backgroundView;
605+
[effectView setEffect:glassEffect];
606+
}
607+
565608
- (void)setEnabled:(BOOL)enabled {
566609
[super setEnabled:enabled];
567610
_containerView.alpha = enabled ? 1 : 0.4;

0 commit comments

Comments
 (0)