macOS开发-NSButton

一.简介

按钮,主要用户通过NSControl控制点击、高亮等事件,同iOSUIButton

@interface NSButton : NSControl 
/**
*   NSButton 定义于 AppKit 框架;
*   NSButton 继承 NSControl
*/ 

二.源码

1.创建NSButton

// 创建带有标题和图像的标准按钮。在从左到右的本地化中,图像显示在标题的左侧。在从右到左的本地化中,它显示在右侧。
+ (instancetype)buttonWithTitle:(NSString *)title image:(NSImage *)image target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 创建带有标题的标准按钮。
+ (instancetype)buttonWithTitle:(NSString *)title target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 使用提供的图像创建标准按钮。设置图像的accessibilityDescription属性以确保此控件的可访问性。
+ (instancetype)buttonWithImage:(NSImage *)image target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 使用提供的标题创建标准复选框。
+ (instancetype)checkboxWithTitle:(NSString *)title target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 使用提供的标题创建标准单选按钮。s
+ (instancetype)radioButtonWithTitle:(NSsString *)title target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));

2.按钮基础配置

typedef NS_ENUM(NSUInteger, NSButtonType) {
    NSButtonTypeMomentaryLight    = 0,
    NSButtonTypePushOnPushOff     = 1,
    NSButtonTypeToggle            = 2,
    NSButtonTypeSwitch            = 3,// 勾选框,不支持带图片,适合做多选
    NSButtonTypeRadio             = 4,// 勾选框,不支持带图片,适合做单选。
    NSButtonTypeMomentaryChange   = 5,// 文字会闪烁
    NSButtonTypeOnOff             = 6,
    NSButtonTypeMomentaryPushIn   = 7,
    NSButtonTypeAccelerator API_AVAILABLE(macos(10.10.3)) = 8,
    NSButtonTypeMultiLevelAccelerator API_AVAILABLE(macos(10.10.3)) = 9,
};
// 设置按钮类型,如上NSButtonType枚举
- (void)setButtonType:(NSButtonType)type;
// 显示文本
@property (copy) NSString *title;
// 富文本
@property (copy) NSAttributedString *attributedTitle;
// 按钮打开状态时的标题,部分类型不显示备用标题
@property (copy) NSString *alternateTitle;
// 富文本按钮打开时的标题
@property (copy) NSAttributedString *attributedAlternateTitle;
// 按钮点击时的播放声音,默认为nil
@property (nullable, strong) NSSound *sound;
// 拖动时发送长按或长时间悬停时的操作。默认为否。
@property (getter=isSpringLoaded) BOOL springLoaded API_AVAILABLE(macos(10.10.3));
// 配置NSMultiLevelAcceleratorButton的最大允许级别,允许的值范围为[1,5]。默认为2。
@property NSInteger maxAcceleratorLevel API_AVAILABLE(macos(10.10.3));
// 为“continuous”为“YES”时发送的重复操作消息设置初始延迟和重复间隔(以秒为单位)。
- (void)setPeriodicDelay:(float)delay interval:(float)interval;
/*! 获取在“continuous”为YES时发送的重复操作消息的初始延迟和重复间隔(以秒为单位)。此方法的两个参数都不能为NULL。*/
- (void)getPeriodicDelay:(float *)delay interval:(float *)interval;

3.配置按钮图片

typedef NS_ENUM(NSUInteger, NSBezelStyle) {
    NSBezelStyleRounded           = 1,
    NSBezelStyleRegularSquare     = 2,
    NSBezelStyleDisclosure        = 5,
    NSBezelStyleShadowlessSquare  = 6,
    NSBezelStyleCircular          = 7,
    NSBezelStyleTexturedSquare    = 8,
    NSBezelStyleHelpButton        = 9,
    NSBezelStyleSmallSquare       = 10,
    NSBezelStyleTexturedRounded   = 11,
    NSBezelStyleRoundRect         = 12,
    NSBezelStyleRecessed          = 13,
    NSBezelStyleRoundedDisclosure = 14,
    NSBezelStyleInline API_AVAILABLE(macos(10.7)) = 15,
};
/*! 按钮系统边框样式 */
@property NSBezelStyle bezelStyle;
/*! 是否绘制边框,bordered为NO时,bezelStyle设置无效 */
@property (getter=isBordered) BOOL bordered;
/*! 按钮是否透明 */
@property (getter=isTransparent) BOOL transparent;
/*! 按钮是否仅在指针位于按钮上方时才显示其边框。 */
@property BOOL showsBorderOnlyWhileMouseInside;
/*! 按钮上的图片、设置nil时不显示图片 */
@property (nullable, strong) NSImage *image;
/*! 按钮处于打开状态上的替代图片,部分类型不支持 */
@property (nullable, strong) NSImage *alternateImage;

typedef NS_ENUM(NSUInteger, NSCellImagePosition) {
    NSNoImage       = 0,// 没有图片
    NSImageOnly     = 1,// 只显示图片
    NSImageLeft     = 2,// 图片在左
    NSImageRight    = 3,// 图片在右
    NSImageBelow    = 4,// 图片在下
    NSImageAbove    = 5,// 图片在上
    NSImageOverlaps = 6,// 图片文字重叠
    NSImageLeading  API_AVAILABLE(macos(10.12)) = 7,// 前导
    NSImageTrailing API_AVAILABLE(macos(10.12)) = 8 // 尾随
};
/*! 图片相对于标题的位置,NSCellImagePosition类型如是上枚举 */
@property NSCellImagePosition imagePosition;

typedef NS_ENUM(NSUInteger, NSImageScaling) {
    NSImageScaleProportionallyDown = 0, // 如果图像对于目的地太大,则将其缩小。保持纵横比。
    NSImageScaleAxesIndependently,      // 缩放每个维度以完全适合目的地。不保留纵横比。
    NSImageScaleNone,                   // 不缩放.
    NSImageScaleProportionallyUpOrDown, // 将图像缩放到最大可能的尺寸,同时(1)停留在目标区域内(2)保持纵横比
    NSScaleProportionally API_DEPRECATED("Use NSImageScaleProportionallyDown instead", macos(10.0,10.10)) = 0,
    NSScaleToFit API_DEPRECATED("Use NSImageScaleAxesIndependently instead", macos(10.0,10.10)),
    NSScaleNone API_DEPRECATED("Use NSImageScaleNone instead", macos(10.0,10.10))
} API_AVAILABLE(macos(10.5));
/*! 缩放 */
@property NSImageScaling imageScaling API_AVAILABLE(macos(10.5));s
/*! 一个布尔值,用于确定按钮的图像和标题在按钮边框中的位置。如果为false,则根据按钮挡板边缘的imagePosition属性定位图像,并且标题位于剩余空间内。如果为true,则基于imagePosition属性将按钮的图像直接定位到标题的旁边,并且图像和标题作为单个单元定位在按钮挡板中。 */
@property BOOL imageHugsTitle API_AVAILABLE(macos(10.12));
/*! 将自定义颜色应用于按钮的边框(在支持它的外观中)。零值表示未修改的按钮外观。默认值为零。 */
@property (nullable, copy) NSColor *bezelColor API_AVAILABLE(macos(10.12.2));
/*! 将淡色应用于模板图像和文本内容,并结合其他适合主题的效果。仅适用于无边界按钮。零值表示没有颜色修改的标准效果集。默认值为零。非模板图像和属性化字符串值不受contentTintColor的影响。 */
@property (nullable, copy) NSColor *contentTintColor API_AVAILABLE(macos(10.14));

4.按钮状态

typedef NSInteger NSControlStateValue NS_TYPED_EXTENSIBLE_ENUM;
static const NSControlStateValue NSControlStateValueMixed = -1;
static const NSControlStateValue NSControlStateValueOff = 0;
static const NSControlStateValue NSControlStateValueOn = 1; 
/*! 按钮的状态。按钮支持关闭和打开状态,以及根据“allowsMixedState”属性的值附加的混合状态。 */
@property NSControlStateValue state;
/*! 指示按钮是否允许混合状态的布尔值。如果否,按钮有两种状态(开和关),如果是,按钮有三种状态(开、关和混合)。混合状态通常与复选框和单选按钮一起使用,以指示部分启用的值。 */
@property BOOL allowsMixedState;
/*! 将按钮设置为下一个符合条件的状态。如果按钮允许混合状态,则按以下顺序循环状态:打开、关闭、混合、打开等。如果按钮不允许混合状态,则在关闭和打开之间切换。 */
- (void)setNextState;

/*! 突出显示或取消突出显示按钮。高亮显示使按钮显示为“按下”,这可能包括显示照明挡板,或显示替代图像或标题,具体取决于按钮的类型。*/
- (void)highlight:(BOOL)flag;

5.键盘事件

/*! 此属性包含按钮的键等效项,如果未定义等效项,则包含空字符串。按钮没有默认的等价键。设置与返回字符相等的键将使其充当其窗口的默认按钮。 */
@property (copy) NSString *keyEquivalent;
/*! 一个位掩码,指定应用于按钮的等效键的修改键。掩码位由NSEventModifierFlags选项集定义。按钮键等效修改器掩码中唯一相关的掩码位是NSEventModifierFlagControl、NSEventModifierFlagOption和NSEventModifierFlagCommand。 */
@property NSEventModifierFlags keyEquivalentModifierMask;
/*! 如果事件参数与按钮的等效键匹配,则按钮将短暂高亮显示并执行其操作,然后返回YES。否则,返回NO。 */
- (BOOL)performKeyEquivalent:(NSEvent *)key;

三.macOSiOS 的不同点

1.添加点击事件

iOS:

[button addTarget: action: forControlEvents:];

Mac:

1.需要同时设置 [button setTarget: targetObject:]; [button setAction: @selector(buttonClick:)];

2.初始化的时候添加点击事件

- (void)addButton {
  NSButton *button = [NSButton buttonWithTitle:@"使劲戳" target:self action:@selector(buttonClick:)];
  button.frame = CGRectMake(0, 0, 80, 40);
    [self.view addSubView:button];
}
- (void)buttonClick:(NSButton *)sender {
  // 处理点击事件
}

2.修改文字颜色

macOS不能像iOS一样直接设置文字颜色 [button setTitleColor: forState:]

macOS的设置如下

// 1.无边框可以通过 contentTintColor 设置文字颜色
button.bordered = NO;
button.contentTintColor = NSColor.redColor;
// 2.有边框
NSMutableAttributedString *attrTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[button attributedTitle]];
[attrTitle addAttribute:NSForegroundColorAttributeName value:NSColor.redColor range:NSMakeRange(0, attrTitle.length)];
[attrTitle fixAttributesInRange:NSMakeRange(0, attrTitle.length)];
[button setAttributedTitle:attrTitle];

3.修改背景色

macOS的按钮不能像iOS一样直接设置背景颜色[self setBackgroundColor:],需要在layer层上设置

button.wantsLayer = YES;// 不设置 wantsLayer 背景色设置无效
button.layer.backgroundColor = NSColor.blueColor.CGColor;

4.让按钮点击时不高亮

[(NSButtonCell *)button.cell setHighlightsBy:NSNoCellMask];

5.鼠标悬停在按钮上出现提示文字

button.toolTip = @"瞅啥瞅,快戳啊";

6.修改按钮高度

[button setBezelStyle:NSBezelStyleRegularSquare];

四. 使用NSView创建Button

参考:《macOS开发》自定义控件之NSButton

#import 

NS_ASSUME_NONNULL_BEGIN

typedef enum {
    FSRectCornerTopLeft     = 1 << 0,
    FSRectCornerTopRight    = 1 << 1,
    FSRectCornerBottomLeft  = 1 << 2,
    FSRectCornerBottomRight = 1 << 3,
    FSRectCornerAllCorners  = ~0UL
} FSRectCorner;

typedef enum {
    FSTextAlignmentLeft  = 0, //左对齐
    FSTextAlignmentCenter,    //居中
    FSTextAlignmentRight      //右对齐
    
}FSTextAlignment;

typedef enum {
    FSTextUnderLineStyleNone  = 0,     //无下划线
    FSTextUnderLineStyleSingle,        //单下划线
    FSTextUnderLineStyleDouble,        //双下划线
    FSTextUnderLineStyleDeleteSingle,  //单删除线
    FSTextUnderLineStyleDeleteDouble   //双删除线
    
}FSTextUnderLineStyle;

@interface FSCustomBtn : NSView

@property (nullable, weak) id target;
@property (nullable) SEL action;

/// 当鼠标移动到控件时,是否显示"小手"
@property (assign, nonatomic) BOOL isHandCursor;

///圆角
@property (nonatomic, assign) CGFloat radius;
@property (nonatomic, assign) FSRectCorner rectCorners;

///按钮文字
@property (nonatomic, nullable, strong) NSString *title;
@property (nonatomic, nullable, strong) NSString *selectedTitle;

///按钮文字对齐方式
@property (nonatomic, assign) FSTextAlignment textAlignment;

///按钮文字下划线样式
@property (nonatomic, assign) FSTextUnderLineStyle textUnderLineStyle;

///按钮文字颜色
@property (nonatomic, nullable, strong) NSColor *titleColor;
@property (nonatomic, nullable, strong) NSColor *selectedTitleColor;

///按钮字体
@property (nonatomic, nullable, strong) NSFont *font;
@property (nonatomic, nullable, strong) NSFont *selectedFont;

///当背景图片存在时,背景色无效
@property (nonatomic, nullable, strong) NSImage *backgroundImage;
@property (nonatomic, nullable, strong) NSImage *selectedBackgroundImage;

///当背景图片不存在时,显示背景色
@property (nonatomic, nullable, strong) NSColor *backgroundColor;
@property (nonatomic, nullable, strong) NSColor *selectedBackgroundColor;

@end

NS_ASSUME_NONNULL_END

#import "FSCustomBtn.h"
#import 

#define FSMsgSend(...)       ((void (*)(void *, SEL, id))objc_msgSend)(__VA_ARGS__)
#define FSMsgTarget(target)  (__bridge void *)(target)
@interface FSCustomBtn () {
    NSTrackingArea *_trackingArea;
}

@property (nonatomic,assign) BOOL mouseDown;

@end

@implementation FSCustomBtn

- (void)setMouseDown:(BOOL)mouseDown {
    if (_mouseDown == mouseDown) return;
    
    _mouseDown = mouseDown;
    [self setNeedsDisplay];
}

///圆角
- (void)setRectCorners:(FSRectCorner)rectCorners {
    if (_rectCorners == rectCorners) return;
    
    _rectCorners = rectCorners;
    [self setNeedsDisplay];
}

///半径
- (void)setRadius:(CGFloat)radius {
    if (_radius == radius) return;
    
    _radius = radius;
    [self setNeedsDisplay];
}

///按钮文字
- (void)setTitle:(NSString *)title {
    if ([_title isEqualToString:title]) return;
    _title = title;
    [self setNeedsDisplay];
}

- (void)setSelectedTitle:(NSString *)selectedTitle {
    if ([_selectedTitle isEqualToString:selectedTitle]) return;
    _selectedTitle = selectedTitle;
    [self setNeedsDisplay];
}

///按钮文字对齐方式
- (void)setTextAlignment:(FSTextAlignment)textAlignment {
    if (_textAlignment == textAlignment) return;
    _textAlignment = textAlignment;
    [self setNeedsDisplay];
}

///按钮文字下划线样式
- (void)setTextUnderLineStyle:(FSTextUnderLineStyle)textUnderLineStyle {
    if (_textUnderLineStyle == textUnderLineStyle) return;
    _textUnderLineStyle = textUnderLineStyle;
    [self setNeedsDisplay];
}

///按钮文字颜色
- (void)setTitleColor:(NSColor *)titleColor {
    if (_titleColor == titleColor) return;
    _titleColor = titleColor;
    [self setNeedsDisplay];
}

- (void)setSelectedTitleColor:(NSColor *)selectedTitleColor {
    if (_selectedTitleColor == selectedTitleColor) return;
    _selectedTitleColor = selectedTitleColor;
    [self setNeedsDisplay];
}

///按钮字体
- (void)setFont:(NSFont *)font {
    if (_font == font) return;
    _font = font;
    [self setNeedsDisplay];
}

- (void)setSelectedFont:(NSFont *)selectedFont {
    if (_selectedFont == selectedFont) return;
    _selectedFont = selectedFont;
    [self setNeedsDisplay];
}

///当背景图片存在时,背景色无效
- (void)setBackgroundImage:(NSImage *)backgroundImage {
    if (_backgroundImage == backgroundImage) return;
    _backgroundImage = backgroundImage;
    [self setNeedsDisplay];
}

- (void)setSelectedBackgroundImage:(NSImage *)selectedBackgroundImage {
    if (_selectedBackgroundImage == selectedBackgroundImage) return;
    _selectedBackgroundImage = selectedBackgroundImage;
    [self setNeedsDisplay];
}

///当背景图片不存在时,显示背景色
- (void)setBackgroundColor:(NSColor *)backgroundColor {
    if (_backgroundColor == backgroundColor) return;
    _backgroundColor = backgroundColor;
    [self setNeedsDisplay];
}

- (void)setSelectedBackgroundColor:(NSColor *)selectedBackgroundColor {
    if (_selectedBackgroundColor == selectedBackgroundColor) return;
    _selectedBackgroundColor = selectedBackgroundColor;
    [self setNeedsDisplay];
}

- (void)setNeedsDisplay {
    if (self.superview) {
        [self setNeedsDisplay:YES];
    }
}

-(void)updateTrackingAreas {
    if (_trackingArea == nil) {
        _trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds
                                                     options:NSTrackingMouseEnteredAndExited|NSTrackingActiveInKeyWindow
                                                       owner:self
                                                    userInfo:nil];
        [self addTrackingArea:_trackingArea];
    }
}

-(void)mouseEntered:(NSEvent *)theEvent{
    if (_isHandCursor == NO) return;
    [[NSCursor pointingHandCursor] set];
}

-(void)mouseExited:(NSEvent *)theEvent{
    if (_isHandCursor == NO) return;
    [[NSCursor arrowCursor] set];
}

- (void)mouseDown:(NSEvent *)event {
    NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
    if (CGRectContainsPoint(self.bounds, point)) {
        self.mouseDown = YES;
    }
}

- (void)mouseUp:(NSEvent *)event {
    if (self.mouseDown) {
        self.mouseDown = NO;
        [self setNeedsDisplay:YES];
        
        NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
        if (CGRectContainsPoint(self.bounds, point)) {
            
            if (self.target && self.action && [self.target respondsToSelector:self.action]) {
                FSMsgSend(FSMsgTarget(self.target), self.action, self);
            }
        }
    }
}

- (void)drawRect:(NSRect)dirtyRect {
    
    NSString *title      = nil;
    NSFont   *font       = nil;
    NSColor  *titleColor = nil;
    NSColor  *backgroundColor = nil;
    NSImage  *backgroundImage = nil;
    
    if (self.mouseDown) {
        title = self.selectedTitle;
        font  = self.selectedFont;
        titleColor = self.selectedTitleColor;
        backgroundColor = self.selectedBackgroundColor;
        backgroundImage = self.selectedBackgroundImage;
        
        if (title == nil) {
            title = self.title;
        }
        if (font == nil) {
            font  = self.font;
        }
        if (titleColor == nil) {
            titleColor = self.titleColor;
        }
        if (backgroundColor == nil) {
            backgroundColor = self.backgroundColor;
        }
        if (backgroundImage == nil) {
            backgroundImage = self.backgroundImage;
        }
    }
    else {
        title = self.title;
        font  = self.font;
        titleColor = self.titleColor;
        backgroundColor = self.backgroundColor;
        backgroundImage = self.backgroundImage;
    }
    
    if (title == nil) {
        title = @"按钮";
    }
    if (font == nil) {
        font = [NSFont systemFontOfSize:17];
    }
    if (titleColor == nil) {
        titleColor = [NSColor blackColor];
    }
    if (backgroundImage) {
        backgroundColor = [NSColor colorWithPatternImage:backgroundImage];
    }
    else {
        if (backgroundColor == nil) {
            backgroundColor = [NSColor clearColor];
        }
    }
    
    if (_rectCorners) {
        NSBezierPath *bezierPath;
        if (_rectCorners == FSRectCornerAllCorners) {
            bezierPath = [NSBezierPath bezierPathWithRoundedRect:dirtyRect xRadius:_radius yRadius:_radius];
        }
        else {
            bezierPath = [NSBezierPath bezierPath];
            
            CGFloat topRightRadius = 0.0, topLeftRadius = 0.0, bottomLeftRadius = 0.0, bottomRightRadius = 0.0;
            
            if (_rectCorners & FSRectCornerTopRight) {
                topRightRadius = _radius;
            }
            if (_rectCorners & FSRectCornerTopLeft) {
                topLeftRadius = _radius;
            }
            if (_rectCorners & FSRectCornerBottomLeft) {
                bottomLeftRadius = _radius;
            }
            if (_rectCorners & FSRectCornerBottomRight) {
                bottomRightRadius = _radius;
            }
            
            //右上
            CGPoint topRightPoint = CGPointMake(dirtyRect.origin.x+dirtyRect.size.width, dirtyRect.origin.y+dirtyRect.size.height);
            topRightPoint.x -= topRightRadius;
            topRightPoint.y -= topRightRadius;
            [bezierPath appendBezierPathWithArcWithCenter:topRightPoint radius:topRightRadius startAngle:0 endAngle:90];
            
            //左上
            CGPoint topLeftPoint = CGPointMake(dirtyRect.origin.x, dirtyRect.origin.y+dirtyRect.size.height);
            topLeftPoint.x += topLeftRadius;
            topLeftPoint.y -= topLeftRadius;
            [bezierPath appendBezierPathWithArcWithCenter:topLeftPoint radius:topLeftRadius startAngle:90 endAngle:180];
            
            //左下
            CGPoint bottomLeftPoint = dirtyRect.origin;
            bottomLeftPoint.x += bottomLeftRadius;
            bottomLeftPoint.y += bottomLeftRadius;
            [bezierPath appendBezierPathWithArcWithCenter:bottomLeftPoint radius:bottomLeftRadius startAngle:180 endAngle:270];
            
            //右下
            CGPoint bottomRightPoint = CGPointMake(dirtyRect.origin.x+dirtyRect.size.width, dirtyRect.origin.y);
            bottomRightPoint.x -= bottomRightRadius;
            bottomRightPoint.y += bottomRightRadius;
            [bezierPath appendBezierPathWithArcWithCenter:bottomRightPoint radius:bottomRightRadius startAngle:270 endAngle:360];
        }
        [backgroundColor setFill];
        [bezierPath fill];
    }
    else {
        [backgroundColor setFill];
        NSRectFill(dirtyRect);
    }
    
    if (title) {
        
        //绘制文字
        NSMutableAttributedString *attTitle = [[NSMutableAttributedString alloc] initWithString:title];
        
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
        paragraphStyle.lineSpacing = 1;
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
        NSDictionary *attributes = @{NSFontAttributeName:font,
                                     NSParagraphStyleAttributeName:paragraphStyle,
                                     NSForegroundColorAttributeName:titleColor};
        
        [attTitle addAttributes:attributes range:NSMakeRange(0, attTitle.length)];
        
        if (self.textUnderLineStyle == FSTextUnderLineStyleSingle) {
            NSUnderlineStyle style = NSUnderlineStyleSingle;
            [attTitle addAttributes:@{NSUnderlineStyleAttributeName:@(style)} range:NSMakeRange(0, attTitle.length)];
            [attTitle addAttributes:@{NSUnderlineColorAttributeName:titleColor} range:NSMakeRange(0, attTitle.length)];
        }
        else if (self.textUnderLineStyle == FSTextUnderLineStyleDouble) {
            NSUnderlineStyle style = NSUnderlineStyleDouble;
            [attTitle addAttributes:@{NSUnderlineStyleAttributeName:@(style)} range:NSMakeRange(0, attTitle.length)];
            [attTitle addAttributes:@{NSUnderlineColorAttributeName:titleColor} range:NSMakeRange(0, attTitle.length)];
        }
        else if (self.textUnderLineStyle == FSTextUnderLineStyleDeleteSingle) {
            [attTitle addAttributes:@{NSStrikethroughStyleAttributeName:@(NSUnderlinePatternSolid|NSUnderlineStyleSingle),
                                      NSStrikethroughColorAttributeName:titleColor}
                          range:NSMakeRange(0, attTitle.length)];
        }
        else if (self.textUnderLineStyle == FSTextUnderLineStyleDeleteDouble) {
            [attTitle addAttributes:@{NSStrikethroughStyleAttributeName:@(NSUnderlinePatternSolid|NSUnderlineStyleDouble),
                                      NSStrikethroughColorAttributeName:titleColor}
                              range:NSMakeRange(0, attTitle.length)];
        }
        
        CGSize titleSize = [attTitle.string boundingRectWithSize:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
        
        CGRect titleRect;
        if (self.textAlignment == FSTextAlignmentLeft) {
            titleRect = CGRectMake(0,
                                   (self.bounds.size.height-titleSize.height)/2.0,
                                   titleSize.width,
                                   titleSize.height);
        }
        else if (self.textAlignment == FSTextAlignmentCenter) {
            titleRect = CGRectMake((self.bounds.size.width-titleSize.width)/2.0,
                                   (self.bounds.size.height-titleSize.height)/2.0,
                                   titleSize.width,
                                   titleSize.height);
        }
        else {
            titleRect = CGRectMake((self.bounds.size.width-titleSize.width),
                                   (self.bounds.size.height-titleSize.height)/2.0,
                                   titleSize.width,
                                   titleSize.height);
        }
        [attTitle drawInRect:titleRect];
    }
}

- (void)removeFromSuperview {
    if (_trackingArea) {
        [self removeTrackingArea:_trackingArea];
    }
    [super removeFromSuperview];
}

@end

调用

- (void)viewDidLoad {
    [super viewDidLoad];

    FSCustomBtn *btn = [[FSCustomBtn alloc] initWithFrame:CGRectMake(10, 10, 100, 60)];
    btn.isHandCursor = YES;
    btn.target = self;
    btn.backgroundColor = NSColor.whiteColor;
    btn.selectedBackgroundColor = NSColor.lightGrayColor;
    btn.titleColor = NSColor.redColor;
    btn.selectedTitleColor = NSColor.greenColor;
    btn.textAlignment = FSTextAlignmentCenter;
    btn.rectCorners = FSRectCornerTopLeft | FSRectCornerBottomRight;
    btn.radius = 20;
    [btn setAction:@selector(btnClick:)];
    [self.view addSubview:btn];
}

FSToolbarDemo

你可能感兴趣的:(macOS开发-NSButton)