macOS開發(fā)-NSButton

一.簡介

按鈕咸灿,主要用戶通過NSControl控制點擊、高亮等事件诫龙,同iOSUIButton

@interface NSButton : NSControl <NSUserInterfaceValidations, NSAccessibilityButton, NSUserInterfaceCompression>
/**
*   NSButton 定義于 AppKit 框架析显;
*   NSButton 繼承 NSControl
*/ 

二.源碼

1.創(chuàng)建NSButton

// 創(chuàng)建帶有標題和圖像的標準按鈕。在從左到右的本地化中签赃,圖像顯示在標題的左側(cè)谷异。在從右到左的本地化中,它顯示在右側(cè)锦聊。
+ (instancetype)buttonWithTitle:(NSString *)title image:(NSImage *)image target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 創(chuàng)建帶有標題的標準按鈕歹嘹。
+ (instancetype)buttonWithTitle:(NSString *)title target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 使用提供的圖像創(chuàng)建標準按鈕。設(shè)置圖像的accessibilityDescription屬性以確保此控件的可訪問性孔庭。
+ (instancetype)buttonWithImage:(NSImage *)image target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 使用提供的標題創(chuàng)建標準復(fù)選框尺上。
+ (instancetype)checkboxWithTitle:(NSString *)title target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));
// 使用提供的標題創(chuàng)建標準單選按鈕材蛛。s
+ (instancetype)radioButtonWithTitle:(NSsString *)title target:(nullable id)target action:(nullable SEL)action API_AVAILABLE(macos(10.12));

2.按鈕基礎(chǔ)配置

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,
};
// 設(shè)置按鈕類型豆赏,如上NSButtonType枚舉
- (void)setButtonType:(NSButtonType)type;
// 顯示文本
@property (copy) NSString *title;
// 富文本
@property (copy) NSAttributedString *attributedTitle;
// 按鈕打開狀態(tài)時的標題,部分類型不顯示備用標題
@property (copy) NSString *alternateTitle;
// 富文本按鈕打開時的標題
@property (copy) NSAttributedString *attributedAlternateTitle;
// 按鈕點擊時的播放聲音富稻,默認為nil
@property (nullable, strong) NSSound *sound;
// 拖動時發(fā)送長按或長時間懸停時的操作掷邦。默認為否。
@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”時發(fā)送的重復(fù)操作消息設(shè)置初始延遲和重復(fù)間隔(以秒為單位)哪怔。
- (void)setPeriodicDelay:(float)delay interval:(float)interval;
/*! 獲取在“continuous”為YES時發(fā)送的重復(fù)操作消息的初始延遲和重復(fù)間隔(以秒為單位)宣蔚。此方法的兩個參數(shù)都不能為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,
};
/*! 按鈕系統(tǒng)邊框樣式 */
@property NSBezelStyle bezelStyle;
/*! 是否繪制邊框蔓涧,bordered為NO時件已,bezelStyle設(shè)置無效 */
@property (getter=isBordered) BOOL bordered;
/*! 按鈕是否透明 */
@property (getter=isTransparent) BOOL transparent;
/*! 按鈕是否僅在指針位于按鈕上方時才顯示其邊框。 */
@property BOOL showsBorderOnlyWhileMouseInside;
/*! 按鈕上的圖片元暴、設(shè)置nil時不顯示圖片 */
@property (nullable, strong) NSImage *image;
/*! 按鈕處于打開狀態(tài)上的替代圖片篷扩,部分類型不支持 */
@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,// 前導(dǎo)
    NSImageTrailing API_AVAILABLE(macos(10.12)) = 8 // 尾隨
};
/*! 圖片相對于標題的位置,NSCellImagePosition類型如是上枚舉 */
@property NSCellImagePosition imagePosition;

typedef NS_ENUM(NSUInteger, NSImageScaling) {
    NSImageScaleProportionallyDown = 0, // 如果圖像對于目的地太大,則將其縮小。保持縱橫比笤成。
    NSImageScaleAxesIndependently,      // 縮放每個維度以完全適合目的地嗤瞎。不保留縱橫比他嫡。
    NSImageScaleNone,                   // 不縮放.
    NSImageScaleProportionallyUpOrDown, // 將圖像縮放到最大可能的尺寸,同時(1)停留在目標區(qū)域內(nèi)(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连茧,則根據(jù)按鈕擋板邊緣的imagePosition屬性定位圖像,并且標題位于剩余空間內(nèi)巍糯。如果為true啸驯,則基于imagePosition屬性將按鈕的圖像直接定位到標題的旁邊,并且圖像和標題作為單個單元定位在按鈕擋板中祟峦。 */
@property BOOL imageHugsTitle API_AVAILABLE(macos(10.12));
/*! 將自定義顏色應(yīng)用于按鈕的邊框(在支持它的外觀中)罚斗。零值表示未修改的按鈕外觀。默認值為零宅楞。 */
@property (nullable, copy) NSColor *bezelColor API_AVAILABLE(macos(10.12.2));
/*! 將淡色應(yīng)用于模板圖像和文本內(nèi)容针姿,并結(jié)合其他適合主題的效果袱吆。僅適用于無邊界按鈕。零值表示沒有顏色修改的標準效果集距淫。默認值為零绞绒。非模板圖像和屬性化字符串值不受contentTintColor的影響。 */
@property (nullable, copy) NSColor *contentTintColor API_AVAILABLE(macos(10.14));

4.按鈕狀態(tài)

typedef NSInteger NSControlStateValue NS_TYPED_EXTENSIBLE_ENUM;
static const NSControlStateValue NSControlStateValueMixed = -1;
static const NSControlStateValue NSControlStateValueOff = 0;
static const NSControlStateValue NSControlStateValueOn = 1; 
/*! 按鈕的狀態(tài)榕暇。按鈕支持關(guān)閉和打開狀態(tài)处铛,以及根據(jù)“allowsMixedState”屬性的值附加的混合狀態(tài)。 */
@property NSControlStateValue state;
/*! 指示按鈕是否允許混合狀態(tài)的布爾值拐揭。如果否,按鈕有兩種狀態(tài)(開和關(guān))奕塑,如果是堂污,按鈕有三種狀態(tài)(開、關(guān)和混合)龄砰∶瞬混合狀態(tài)通常與復(fù)選框和單選按鈕一起使用,以指示部分啟用的值换棚。 */
@property BOOL allowsMixedState;
/*! 將按鈕設(shè)置為下一個符合條件的狀態(tài)式镐。如果按鈕允許混合狀態(tài),則按以下順序循環(huán)狀態(tài):打開固蚤、關(guān)閉娘汞、混合、打開等夕玩。如果按鈕不允許混合狀態(tài)你弦,則在關(guān)閉和打開之間切換。 */
- (void)setNextState;

/*! 突出顯示或取消突出顯示按鈕燎孟。高亮顯示使按鈕顯示為“按下”禽作,這可能包括顯示照明擋板,或顯示替代圖像或標題揩页,具體取決于按鈕的類型旷偿。*/
- (void)highlight:(BOOL)flag;

5.鍵盤事件

/*! 此屬性包含按鈕的鍵等效項,如果未定義等效項爆侣,則包含空字符串萍程。按鈕沒有默認的等價鍵。設(shè)置與返回字符相等的鍵將使其充當其窗口的默認按鈕累提。 */
@property (copy) NSString *keyEquivalent;
/*! 一個位掩碼尘喝,指定應(yīng)用于按鈕的等效鍵的修改鍵。掩碼位由NSEventModifierFlags選項集定義斋陪。按鈕鍵等效修改器掩碼中唯一相關(guān)的掩碼位是NSEventModifierFlagControl朽褪、NSEventModifierFlagOption和NSEventModifierFlagCommand置吓。 */
@property NSEventModifierFlags keyEquivalentModifierMask;
/*! 如果事件參數(shù)與按鈕的等效鍵匹配,則按鈕將短暫高亮顯示并執(zhí)行其操作缔赠,然后返回YES衍锚。否則,返回NO嗤堰。 */
- (BOOL)performKeyEquivalent:(NSEvent *)key;

三.macOSiOS 的不同點

1.添加點擊事件

iOS:

[button addTarget: action: forControlEvents:];

Mac:

1.需要同時設(shè)置 [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一樣直接設(shè)置文字顏色 [button setTitleColor: forState:]

macOS的設(shè)置如下

// 1.無邊框可以通過 contentTintColor 設(shè)置文字顏色
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一樣直接設(shè)置背景顏色[self setBackgroundColor:]戴质,需要在layer層上設(shè)置

button.wantsLayer = YES;// 不設(shè)置 wantsLayer 背景色設(shè)置無效
button.layer.backgroundColor = NSColor.blueColor.CGColor;

4.讓按鈕點擊時不高亮

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

5.鼠標懸停在按鈕上出現(xiàn)提示文字

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

6.修改按鈕高度

[button setBezelStyle:NSBezelStyleRegularSquare];

四. 使用NSView創(chuàng)建Button

參考:《macOS開發(fā)》自定義控件之NSButton

#import <Cocoa/Cocoa.h>

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 <objc/message.h>

#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

調(diào)用

- (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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市输莺,隨后出現(xiàn)的幾起案子戚哎,更是在濱河造成了極大的恐慌,老刑警劉巖嫂用,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件型凳,死亡現(xiàn)場離奇詭異,居然都是意外死亡嘱函,警方通過查閱死者的電腦和手機甘畅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來实夹,“玉大人橄浓,你說我怎么就攤上這事×梁剑” “怎么了荸实?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缴淋。 經(jīng)常有香客問我准给,道長,這世上最難降的妖魔是什么重抖? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任露氮,我火速辦了婚禮,結(jié)果婚禮上钟沛,老公的妹妹穿的比我還像新娘畔规。我一直安慰自己,他們只是感情好恨统,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布叁扫。 她就那樣靜靜地躺著三妈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪莫绣。 梳的紋絲不亂的頭發(fā)上畴蒲,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音对室,去河邊找鬼模燥。 笑死,一個胖子當著我的面吹牛掩宜,可吹牛的內(nèi)容都是我干的蔫骂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼牺汤,長吁一口氣:“原來是場噩夢啊……” “哼纠吴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慧瘤,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎固该,沒想到半個月后锅减,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡伐坏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年怔匣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桦沉。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡每瞒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纯露,到底是詐尸還是另有隱情剿骨,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布埠褪,位于F島的核電站浓利,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钞速。R本人自食惡果不足惜贷掖,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渴语。 院中可真熱鬧苹威,春花似錦、人聲如沸驾凶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至腹暖,卻和暖如春汇在,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脏答。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工糕殉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人殖告。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓阿蝶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親黄绩。 傳聞我的和親對象是個殘疾皇子羡洁,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348