Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Fixed issues with CALayer + added support for custom disabled state and fixing vertical alignment for specific fonts. #11

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions SYFlatButton/SYFlatButton/SYFlatButton.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ IB_DESIGNABLE
@property (nonatomic, assign) IBInspectable CGFloat spacing; // Default:0.0 - Button's spacint between image and title
@property (nonatomic, strong) IBInspectable NSColor *borderNormalColor; // Default:nil - Button's border color when state off
@property (nonatomic, strong) IBInspectable NSColor *borderHighlightColor; // Default:nil - Button's border color when state on
@property (nonatomic, strong) IBInspectable NSColor *borderDisabledColor; // Default:nil - Button's border color when disabled
@property (nonatomic, strong) IBInspectable NSColor *backgroundNormalColor; // Default:nil - Button's background color when state off
@property (nonatomic, strong) IBInspectable NSColor *backgroundHighlightColor; // Default:nil - Button's background color when state on
@property (nonatomic, strong) IBInspectable NSColor *backgroundDisabledColor; // Default:nil - Button's background color when disabled
@property (nonatomic, strong) IBInspectable NSColor *imageNormalColor; // Default:nil - Button's image color when state off
@property (nonatomic, strong) IBInspectable NSColor *imageHighlightColor; // Default:nil - Button's image color when state on
@property (nonatomic, strong) IBInspectable NSColor *imageDisabledColor; // Default:nil - Button's image color when disabled
@property (nonatomic, strong) IBInspectable NSColor *titleNormalColor; // Default:nil - Button's title color when state off
@property (nonatomic, strong) IBInspectable NSColor *titleHighlightColor; // Default:nil - Button's title color when state on
@property (nonatomic, strong) IBInspectable NSColor *titleDisabledColor; // Default:nil - Button's title color when state on

@end
85 changes: 63 additions & 22 deletions SYFlatButton/SYFlatButton/SYFlatButton.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ @interface SYFlatButton () <CALayerDelegate>
@property (nonatomic, strong) CAShapeLayer *imageLayer;
@property (nonatomic, strong) CATextLayer *titleLayer;
@property (nonatomic, assign) BOOL mouseDown;
@property NSMutableDictionary *fontFamilyNameToYOffsetMap; // used to offet certain fonts so they are properly centered vertically

@end

Expand All @@ -24,8 +25,6 @@ - (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self setup];
[self setupImageLayer];
[self setupTitleLayer];
}
return self;
}
Expand All @@ -34,8 +33,6 @@ - (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
[self setup];
[self setupImageLayer];
[self setupTitleLayer];
}
return self;
}
Expand All @@ -59,11 +56,20 @@ - (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale from

- (void)setup {
// Setup layer
self.layer = [CALayer new];
self.wantsLayer = YES;
self.layer.masksToBounds = YES;
self.layer.delegate = self;
self.layer.backgroundColor = [NSColor redColor].CGColor;
self.alphaValue = self.isEnabled ? 1.0 : 0.5;

// setup the list of custom y-offsets for specific fonts so they are vertically aligned
self.fontFamilyNameToYOffsetMap = [NSMutableDictionary new];
self.fontFamilyNameToYOffsetMap[@"Titillium Web"] = @(-4);

// setup the rest of the control
[self setupImageLayer];
[self setupTitleLayer];
[self animateColorForCurrentState];
}

- (void)setupImageLayer {
Expand Down Expand Up @@ -145,7 +151,14 @@ - (void)setupTitleLayer {
CGSize titleSize = [self.title sizeWithAttributes:@{NSFontAttributeName: self.font}];
CGFloat x = 0.0; // Title's origin x
CGFloat y = 0.0; // Title's origin y


// check if this font needs a specific fix to be centered vertically
// (some fonts display too much white space above or below the text)
if ([self.fontFamilyNameToYOffsetMap objectForKey:self.font.familyName] != nil) {
NSNumber *yOffset = self.fontFamilyNameToYOffsetMap[self.font.familyName];
titleSize.height += yOffset.floatValue;
}

// Caculate the image's and title's position depends on button's imagePosition and imageHugsTitle property
switch (self.imagePosition) {
case NSImageOnly: {
Expand Down Expand Up @@ -194,6 +207,8 @@ - (void)setupTitleLayer {
self.titleLayer.string = self.title;
self.titleLayer.font = (__bridge CFTypeRef _Nullable)(self.font);
self.titleLayer.fontSize = self.font.pointSize;
self.titleLayer.contentsScale = NSScreen.mainScreen.backingScaleFactor; // this is necessary so the text isn't blurry

[self.layer addSublayer:self.titleLayer];
}

Expand All @@ -206,13 +221,14 @@ - (void)removeAllAnimations {
}];
}

- (void)animateColorWithState:(NSCellStateValue)state {
- (void)animateColorForCurrentState {
[self removeAllAnimations];
CGFloat duration = (state == NSOnState) ? self.onAnimateDuration : self.offAnimateDuration;
NSColor *borderColor = (state == NSOnState) ? self.borderHighlightColor : self.borderNormalColor;
NSColor *backgroundColor = (state == NSOnState) ? self.backgroundHighlightColor : self.backgroundNormalColor;
NSColor *titleColor = (state == NSOnState) ? self.titleHighlightColor : self.titleNormalColor;
NSColor *imageColor = (state == NSOnState) ? self.imageHighlightColor : self.imageNormalColor;
CGFloat duration = (self.state == NSOnState) ? self.onAnimateDuration : self.offAnimateDuration;

NSColor *borderColor = (self.isEnabled == NO) ? self.borderDisabledColor : (self.state == NSOnState) ? self.borderHighlightColor : self.borderNormalColor;
NSColor *backgroundColor = (self.isEnabled == NO) ? self.backgroundDisabledColor : (self.state == NSOnState) ? self.backgroundHighlightColor : self.backgroundNormalColor;
NSColor *titleColor = (self.isEnabled == NO) ? self.titleDisabledColor : (self.state == NSOnState) ? self.titleHighlightColor : self.titleNormalColor;
NSColor *imageColor = (self.isEnabled == NO) ? self.imageDisabledColor : (self.state == NSOnState) ? self.imageHighlightColor : self.imageNormalColor;
[self animateLayer:self.layer color:borderColor keyPath:@"borderColor" duration:duration];
[self animateLayer:self.layer color:backgroundColor keyPath:@"backgroundColor" duration:duration];
[self animateLayer:self.imageLayer color:imageColor keyPath:@"backgroundColor" duration:duration];
Expand Down Expand Up @@ -292,7 +308,7 @@ - (void)setImage:(NSImage *)image {

- (void)setState:(NSInteger)state {
[super setState:state];
[self animateColorWithState:state];
[self animateColorForCurrentState];
}

- (void)setImagePosition:(NSCellImagePosition)imagePosition {
Expand All @@ -303,7 +319,7 @@ - (void)setImagePosition:(NSCellImagePosition)imagePosition {

- (void)setMomentary:(BOOL)momentary {
_momentary = momentary;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setCornerRadius:(CGFloat)cornerRadius {
Expand All @@ -324,42 +340,67 @@ - (void)setSpacing:(CGFloat)spacing {

- (void)setBorderNormalColor:(NSColor *)borderNormalColor {
_borderNormalColor = borderNormalColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setBorderHighlightColor:(NSColor *)borderHighlightColor {
_borderHighlightColor = borderHighlightColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setBorderDisabledColor:(NSColor *)borderDisabledColor {
_borderDisabledColor = borderDisabledColor;
[self animateColorForCurrentState];
}

- (void)setBackgroundNormalColor:(NSColor *)backgroundNormalColor {
_backgroundNormalColor = backgroundNormalColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setBackgroundHighlightColor:(NSColor *)backgroundHighlightColor {
_backgroundHighlightColor = backgroundHighlightColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setBackgroundDisabledColor:(NSColor *)backgroundDisabledColor {
_backgroundDisabledColor = backgroundDisabledColor;
[self animateColorForCurrentState];
}

- (void)setImageNormalColor:(NSColor *)imageNormalColor {
_imageNormalColor = imageNormalColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setImageHighlightColor:(NSColor *)imageHighlightColor {
_imageHighlightColor = imageHighlightColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setImageDisabledColor:(NSColor *)imageDisabledColor {
_imageDisabledColor = imageDisabledColor;
[self animateColorForCurrentState];
}

- (void)setTitleNormalColor:(NSColor *)titleNormalColor {
_titleNormalColor = titleNormalColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setTitleHighlightColor:(NSColor *)titleHighlightColor {
_titleHighlightColor = titleHighlightColor;
[self animateColorWithState:self.state];
[self animateColorForCurrentState];
}

- (void)setTitleDisabledColor:(NSColor *)titleDisabledColor {
_titleDisabledColor = titleDisabledColor;
[self animateColorForCurrentState];
}

- (void)setEnabled:(BOOL)enabled {
super.enabled = enabled;
[self animateColorForCurrentState];
}

- (CAShapeLayer *)imageLayer {
Expand Down