Skip to content

Commit

Permalink
Added new APIs for content view integration
Browse files Browse the repository at this point in the history
  • Loading branch information
TimOliver committed Oct 1, 2023
1 parent aff8bdb commit 02700ec
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 46 deletions.
47 changes: 34 additions & 13 deletions TORoundedButton/TORoundedButton.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,38 @@ NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(RoundedButton)
IB_DESIGNABLE @interface TORoundedButton : UIControl

/// The text that is displayed in center of the button (Default is "Button").
@property (nonatomic, copy) IBInspectable NSString *text;

/// The attributed string used in the label of this button. See `UILabel.attributedText` documentation for full details (Default is nil).
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;

/// The radius of the corners of this button (Default is 12.0f).
@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
/// this property to your own custom UIView subclass in order to more efficiently manage sizing and layout.
@property (nonatomic, strong, null_resettable) UIView *contentView;

/// The text that is displayed in center of the button (Default is nil).
@property (nonatomic, copy, nullable) IBInspectable NSString *text;

/// The attributed string used in the label of this button.
/// See `UILabel.attributedText` documentation for full details (Default is nil).
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;

/// The color of the text in this button (Default is white).
@property (nonatomic, strong) IBInspectable UIColor *textColor;

/// When tapped, the level of transparency that the text label animates to. (Defaults to off with 1.0f).
@property (nonatomic, assign) IBInspectable CGFloat tappedTextAlpha;

/// The font of the text in the button (Default is size UIFontTextStyleBody with bold).
/// The font of the text in the button
/// (Default is size UIFontTextStyleBody with bold).
@property (nonatomic, strong) UIFont *textFont;

/// Because IB cannot handle fonts, this can alternatively be used to set the font size. (Default is off with 0.0).
/// Because IB cannot handle fonts, this can alternatively be used to set the font size.
/// (Default is off with 0.0).
@property (nonatomic, assign) IBInspectable CGFloat textPointSize;

/// Taking the default button background color apply a brightness offset for the tapped color (Default is -0.1f. Set 0.0 for off).
/// When tapped, the level of transparency that the text label animates to.
/// (Defaults to off with 1.0f).
@property (nonatomic, assign) IBInspectable CGFloat tappedTextAlpha;

/// Taking the default button background color apply a brightness offset for the tapped color
/// (Default is -0.1f. Set 0.0 for off).
@property (nonatomic, assign) IBInspectable CGFloat tappedTintColorBrightnessOffset;

/// If desired, explicity set the background color of the button when tapped (Default is nil).
Expand All @@ -66,9 +76,20 @@ IB_DESIGNABLE @interface TORoundedButton : UIControl
/// A callback handler triggered each time the button is tapped.
@property (nonatomic, copy) void (^tappedHandler)(void);

/// Create a new instance of a button with the provided text shown in the center. The size will be 288 points wide, and 50 tall.
/// Create a new instance of a button that can be further configured with either text or custom subviews.
/// The size will be 288 points wide, and 50 tall by default.
- (instancetype)init;

/// Create a new instance of a button that can be further configured with either text or custom subviews.
- (instancetype)initWithFrame:(CGRect)frame;

/// Create a new instance of a button with the provided text shown in the center.
/// The size will be 288 points wide, and 50 tall.
- (instancetype)initWithText:(NSString *)text;

/// Create a new instance of a button with the provided view set as the hosting content view.
- (instancetype)initWithContentView:(__kindof UIView *)contentView;

@end

NS_ASSUME_NONNULL_END
Expand Down
90 changes: 57 additions & 33 deletions TORoundedButton/TORoundedButton.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ @implementation TORoundedButton {
or not because the state can change before blocks complete. */
BOOL _isTapped;

/** A container view that holds all of the content view and performs the clipping. */
UIView *_containerView;

/** The title label displaying the text in the center of the button. */
UILabel *_titleLabel;

Expand All @@ -53,13 +50,10 @@ @implementation TORoundedButton {

#pragma mark - View Creation -

- (instancetype)initWithText:(NSString *)text {
- (instancetype)init {
if (self = [super initWithFrame:(CGRect){0,0, 288.0f, 50.0f}]) {
[self _roundedButtonCommonInit];
_titleLabel.text = text;
[_titleLabel sizeToFit];
}

return self;
}

Expand All @@ -79,6 +73,25 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
return self;
}

- (instancetype)initWithContentView:(__kindof UIView *)contentView {
if (self = [super initWithFrame:contentView.bounds]) {
_contentView = contentView;
[self _roundedButtonCommonInit];
}
return self;
}

- (instancetype)initWithText:(NSString *)text {
if (self = [super initWithFrame:(CGRect){0,0, 288.0f, 50.0f}]) {
[self _roundedButtonCommonInit];
[self _makeTitleLabelIfNeeded];
_titleLabel.text = text;
[_titleLabel sizeToFit];
}

return self;
}

- (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
// Default properties (Make sure they're not overriding IB)
_cornerRadius = (_cornerRadius > FLT_EPSILON) ?: 12.0f;
Expand All @@ -91,12 +104,12 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
[self _updateTappedTintColorForTintColor];

// Create the container view that manages the image view and text
_containerView = [[UIView alloc] initWithFrame:self.bounds];
_containerView.backgroundColor = [UIColor clearColor];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_containerView.userInteractionEnabled = NO;
_containerView.clipsToBounds = YES;
[self addSubview:_containerView];
_contentView = [[UIView alloc] initWithFrame:self.bounds];
_contentView.backgroundColor = [UIColor clearColor];
_contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_contentView.userInteractionEnabled = NO;
_contentView.clipsToBounds = YES;
[self addSubview:_contentView];

// Create the image view which will show the button background
_backgroundView = [[UIView alloc] initWithFrame:self.bounds];
Expand All @@ -106,16 +119,23 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
#ifdef __IPHONE_13_0
if (@available(iOS 13.0, *)) { _backgroundView.layer.cornerCurve = kCACornerCurveContinuous; }
#endif
[_containerView addSubview:_backgroundView];

// Create the title label that will display the button text
UIFont *buttonFont = [UIFont systemFontOfSize:17.0f weight:UIFontWeightBold];
if (@available(iOS 11.0, *)) {
// Apply resizable button metrics to font
UIFontMetrics *metrics = [[UIFontMetrics alloc] initForTextStyle:UIFontTextStyleBody];
buttonFont = [metrics scaledFontForFont:buttonFont];
}

[_contentView addSubview:_backgroundView];

// Create action events for all possible interactions with this control
[self addTarget:self action:@selector(_didTouchDownInside) forControlEvents:UIControlEventTouchDown|UIControlEventTouchDownRepeat];
[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];
}

- (void)_makeTitleLabelIfNeeded TOROUNDEDBUTTON_OBJC_DIRECT {
if (_titleLabel) { return; }

// Make the font bold, and opt it into Dynamic Type sizing
UIFontMetrics *const metrics = [[UIFontMetrics alloc] initForTextStyle:UIFontTextStyleBody];
UIFont *const buttonFont = [metrics scaledFontForFont:[UIFont systemFontOfSize:17.0f weight:UIFontWeightBold]];

// Configure the title label
_titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_titleLabel.textAlignment = NSTextAlignmentCenter;
_titleLabel.textColor = [UIColor whiteColor];
Expand All @@ -124,13 +144,7 @@ - (void)_roundedButtonCommonInit TOROUNDEDBUTTON_OBJC_DIRECT {
_titleLabel.backgroundColor = [self _labelBackgroundColor];
_titleLabel.text = @"Button";
_titleLabel.numberOfLines = 0;
[_containerView addSubview:_titleLabel];

// Create action events for all possible interactions with this control
[self addTarget:self action:@selector(_didTouchDownInside) forControlEvents:UIControlEventTouchDown|UIControlEventTouchDownRepeat];
[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];
[_contentView addSubview:_titleLabel];
}

#pragma mark - View Displaying -
Expand All @@ -140,7 +154,7 @@ - (void)layoutSubviews {

// Configure the button text
[_titleLabel sizeToFit];
_titleLabel.center = _containerView.center;
_titleLabel.center = _contentView.center;
_titleLabel.frame = CGRectIntegral(_titleLabel.frame);
}

Expand Down Expand Up @@ -300,7 +314,7 @@ - (void)_setButtonScaledTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DIREC

// Animate the alpha value of the label
void (^animationBlock)(void) = ^{
self->_containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity,
self->_contentView.transform = CGAffineTransformScale(CGAffineTransformIdentity,
scale,
scale);
};
Expand All @@ -323,6 +337,16 @@ - (void)_setButtonScaledTappedAnimated:(BOOL)animated TOROUNDEDBUTTON_OBJC_DIREC

#pragma mark - Public Accessors -

- (void)setContentView:(UIView *)contentView {
if (_contentView == contentView) { return; }

_titleLabel = nil;
[_contentView removeFromSuperview];
_contentView = contentView ?: [UIView new];
[self addSubview:_contentView];
[self setNeedsLayout];
}

- (void)setAttributedText:(NSAttributedString *)attributedText {
_titleLabel.attributedText = attributedText;
[_titleLabel sizeToFit];
Expand Down Expand Up @@ -394,7 +418,7 @@ - (void)setCornerRadius:(CGFloat)cornerRadius {

- (void)setEnabled:(BOOL)enabled {
[super setEnabled:enabled];
_containerView.alpha = enabled ? 1 : 0.4;
_contentView.alpha = enabled ? 1 : 0.4;
}

- (CGFloat)minimumWidth {
Expand Down

0 comments on commit 02700ec

Please sign in to comment.