From b3856c88d0db662954b762c637694178efe6e229 Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Sun, 23 Nov 2025 14:47:26 +0900 Subject: [PATCH 1/4] Added cornerConfiguration for iOS 26 support --- TORoundedButton/TORoundedButton.h | 10 ++++++++-- TORoundedButton/TORoundedButton.m | 31 +++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/TORoundedButton/TORoundedButton.h b/TORoundedButton/TORoundedButton.h index fb73f47..586b3b0 100644 --- a/TORoundedButton/TORoundedButton.h +++ b/TORoundedButton/TORoundedButton.h @@ -25,6 +25,7 @@ NS_ASSUME_NONNULL_BEGIN @class TORoundedButton; +@class UICornerConfiguration; NS_SWIFT_NAME(RoundedButtonDelegate) @protocol TORoundedButtonDelegate @@ -41,8 +42,13 @@ IB_DESIGNABLE @interface TORoundedButton : UIControl /// A delegate object that can receive tap events from this button. @property (nonatomic, weak) id delegate; -/// The radius of the corners of this button (Default is 12.0f). -@property (nonatomic, assign) IBInspectable CGFloat cornerRadius; +/// The corner-rounding behaviour of the button's boundaries. +/// On iOS 26 and above, this is the `.capsule` preset by default. +@property (nonatomic, strong, nullable) UICornerConfiguration *cornerConfiguration API_AVAILABLE(ios(26.0));; + +/// The radius of the corners of this button. +/// (Default is 12.0f on iOS 18 and below. For iOS 26.0, use the `cornerConfiguration` property.) +@property (nonatomic, assign) IBInspectable CGFloat cornerRadius API_DEPRECATED("Use `cornerConfiguration` instead.", ios(10.0, 18.0));; /// The hosting container that manages all of the foreground views in this button. /// You can either add your custom views to this view by default, or you can set diff --git a/TORoundedButton/TORoundedButton.m b/TORoundedButton/TORoundedButton.m index b8f1261..9f1c9ba 100644 --- a/TORoundedButton/TORoundedButton.m +++ b/TORoundedButton/TORoundedButton.m @@ -55,7 +55,7 @@ @implementation TORoundedButton { #pragma mark - View Creation - - (instancetype)init { - if (self = [self initWithFrame:(CGRect){0,0, 288.0f, 50.0f}]) { } + if (self = [self initWithFrame:(CGRect){0,0, 288.0f, 44.0f}]) { } return self; } @@ -86,7 +86,7 @@ - (instancetype)initWithContentView:(__kindof UIView *)contentView { } - (instancetype)initWithText:(NSString *)text { - if (self = [super initWithFrame:(CGRect){0,0, 288.0f, 50.0f}]) { + if (self = [super initWithFrame:(CGRect){0,0, 288.0f, 44.0f}]) { _contentView = [UIView new]; [self _roundedButtonCommonInit]; [self _makeTitleLabelIfNeeded]; @@ -99,7 +99,6 @@ - (instancetype)initWithText:(NSString *)text { - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT { // Default properties (Make sure they're not overriding IB) - _cornerRadius = (_cornerRadius > FLT_EPSILON) ?: 12.0f; _tappedTextAlpha = (_tappedTextAlpha > FLT_EPSILON) ?: 1.0f; _tapAnimationDuration = (_tapAnimationDuration > FLT_EPSILON) ?: 0.4f; _tappedButtonScale = (_tappedButtonScale > FLT_EPSILON) ?: 0.97f; @@ -133,6 +132,13 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT { [self addTarget:self action:@selector(_didTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; [self addTarget:self action:@selector(_didDragOutside) forControlEvents:UIControlEventTouchDragExit|UIControlEventTouchCancel]; [self addTarget:self action:@selector(_didDragInside) forControlEvents:UIControlEventTouchDragEnter]; + + // Set the corner radius depending on app version + if (@available(iOS 26.0, *)) { + self.cornerConfiguration = [UICornerConfiguration capsuleConfiguration]; + } else { + _cornerRadius = (_cornerRadius > FLT_EPSILON) ?: 12.0f; + } } - (void)_makeTitleLabelIfNeeded TOROUNDEDBUTTON_OBJC_DIRECT { @@ -166,7 +172,6 @@ - (UIView *)_makeBackgroundViewWithBlur:(BOOL)withBlur TOROUNDEDBUTTON_OBJC_DIRE } backgroundView.frame = self.bounds; backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - backgroundView.layer.cornerRadius = _cornerRadius; #ifdef __IPHONE_13_0 if (@available(iOS 13.0, *)) { backgroundView.layer.cornerCurve = kCACornerCurveContinuous; } #endif @@ -511,12 +516,26 @@ - (void)setCornerRadius:(CGFloat)cornerRadius { if (fabs(cornerRadius - _cornerRadius) < FLT_EPSILON) { return; } - + _cornerRadius = cornerRadius; - _backgroundView.layer.cornerRadius = _cornerRadius; + + if (@available(iOS 26.0, *)) { + UICornerRadius *const radius = [UICornerRadius fixedRadius:_cornerRadius]; + _backgroundView.cornerConfiguration = [UICornerConfiguration configurationWithUniformRadius:radius]; + } else { + _backgroundView.layer.cornerRadius = _cornerRadius; + } [self setNeedsLayout]; } +- (void)setCornerConfiguration:(UICornerConfiguration *)cornerConfiguration { + _backgroundView.cornerConfiguration = cornerConfiguration; +} + +- (UICornerConfiguration *)cornerConfiguration { + return _backgroundView.cornerConfiguration; +} + - (void)setIsTranslucent:(BOOL)isTranslucent { if (_isTranslucent == isTranslucent) { return; From 10e647ce97b9b94a01d282d13b1df0d1faa274d7 Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Sun, 23 Nov 2025 14:48:27 +0900 Subject: [PATCH 2/4] Made cornerRadius property smarter at working with corner config --- TORoundedButton/TORoundedButton.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TORoundedButton/TORoundedButton.h b/TORoundedButton/TORoundedButton.h index 586b3b0..6e5a4c6 100644 --- a/TORoundedButton/TORoundedButton.h +++ b/TORoundedButton/TORoundedButton.h @@ -47,8 +47,8 @@ IB_DESIGNABLE @interface TORoundedButton : UIControl @property (nonatomic, strong, nullable) UICornerConfiguration *cornerConfiguration API_AVAILABLE(ios(26.0));; /// The radius of the corners of this button. -/// (Default is 12.0f on iOS 18 and below. For iOS 26.0, use the `cornerConfiguration` property.) -@property (nonatomic, assign) IBInspectable CGFloat cornerRadius API_DEPRECATED("Use `cornerConfiguration` instead.", ios(10.0, 18.0));; +/// (Default is 12.0f on iOS 18 and below. For iOS 26.0, changing this property will update `cornerConfiguration`.) +@property (nonatomic, assign) IBInspectable CGFloat cornerRadius; /// The hosting container that manages all of the foreground views in this button. /// You can either add your custom views to this view by default, or you can set From dd8eb13a0f21fe5802723d9031c25c4b29fd3f26 Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Sun, 23 Nov 2025 14:49:55 +0900 Subject: [PATCH 3/4] Cleaned up constant usage --- TORoundedButton/TORoundedButton.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/TORoundedButton/TORoundedButton.m b/TORoundedButton/TORoundedButton.m index 9f1c9ba..96646d8 100644 --- a/TORoundedButton/TORoundedButton.m +++ b/TORoundedButton/TORoundedButton.m @@ -205,7 +205,6 @@ - (void)layoutSubviews { // Lay out the title label if (!_titleLabel) { return; } - [_titleLabel sizeToFit]; _titleLabel.center = (CGPoint){ .x = CGRectGetMidX(_contentView.bounds), @@ -276,7 +275,7 @@ - (UIColor *)_labelBackgroundColor TOROUNDEDBUTTON_OBJC_DIRECT { if (_isTapped || _isTranslucent) { return [UIColor clearColor]; } // Return clear if the tint color isn't opaque - BOOL isClear = CGColorGetAlpha(self.tintColor.CGColor) < (1.0f - FLT_EPSILON); + const BOOL isClear = CGColorGetAlpha(self.tintColor.CGColor) < (1.0f - FLT_EPSILON); return isClear ? [UIColor clearColor] : self.tintColor; } @@ -366,7 +365,7 @@ - (void)_setBackgroundColorTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DI - (void)_setLabelAlphaTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DIRECT { if (_tappedTextAlpha > 1.0f - FLT_EPSILON) { return; } - CGFloat alpha = _isTapped ? _tappedTextAlpha : 1.0f; + const CGFloat alpha = _isTapped ? _tappedTextAlpha : 1.0f; // Animate the alpha value of the label void (^animationBlock)(void) = ^{ @@ -397,7 +396,7 @@ - (void)_setLabelAlphaTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DIRECT - (void)_setButtonScaledTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DIRECT { if (_tappedButtonScale < FLT_EPSILON) { return; } - CGFloat scale = _isTapped ? _tappedButtonScale : 1.0f; + const CGFloat scale = _isTapped ? _tappedButtonScale : 1.0f; // Animate the alpha value of the label void (^animationBlock)(void) = ^{ From f05ca705de1fab6dc307fa666646329685a9acdb Mon Sep 17 00:00:00 2001 From: Tim Oliver Date: Sun, 23 Nov 2025 14:54:10 +0900 Subject: [PATCH 4/4] Fixed a typo in iOS 26 header --- TORoundedButton/TORoundedButton.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TORoundedButton/TORoundedButton.h b/TORoundedButton/TORoundedButton.h index 6e5a4c6..ed5b2fe 100644 --- a/TORoundedButton/TORoundedButton.h +++ b/TORoundedButton/TORoundedButton.h @@ -44,7 +44,7 @@ IB_DESIGNABLE @interface TORoundedButton : UIControl /// The corner-rounding behaviour of the button's boundaries. /// On iOS 26 and above, this is the `.capsule` preset by default. -@property (nonatomic, strong, nullable) UICornerConfiguration *cornerConfiguration API_AVAILABLE(ios(26.0));; +@property (nonatomic, strong, nullable) UICornerConfiguration *cornerConfiguration API_AVAILABLE(ios(26.0)); /// The radius of the corners of this button. /// (Default is 12.0f on iOS 18 and below. For iOS 26.0, changing this property will update `cornerConfiguration`.)