macOS 開(kāi)發(fā)問(wèn)題匯總

目錄 11+

11. macOS 調(diào)用framework中類別的方法 編譯成功但運(yùn)行報(bào)錯(cuò)
12. macOS語(yǔ)言本地化/國(guó)際化同iOS一致,參見(jiàn):iOS語(yǔ)言本地化/國(guó)際化一些技巧
13. macOS 打包問(wèn)題記錄
14. macOS 完全清理App
15. xib嵌套
16. macOS 修改App名稱
17. macOS App Main Menu 工具欄

目錄1-10

1. 瀏覽器打開(kāi)URL

  [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.baidu.com"]];

2. NSTextField超鏈接

//policy
NSFont *font = [NSFont systemFontOfSize:12];
attStr = [[NSMutableAttributedString alloc] initWithString:@"登錄即同意《用戶協(xié)議》和《隱私政策》"];
[attStr addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 18)];
[attStr addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithRed:175.0f/255.0f green:174.0f/255.0f blue:174.0f/255.0f alpha:1.0f] range:NSMakeRange(0, 18)];
NSRange range = [[attStr string] rangeOfString:@"《用戶協(xié)議》"];

//policy-1
[attStr addAttribute:NSFontAttributeName value:font range:range];
[attStr addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithRed:5.0f/255.0f green:164.0f/255.0f blue:255.0f/255.0f alpha:1.0f] range:range];;
[attStr addAttribute:NSLinkAttributeName value:kCFPrivacyTerms_URL range:range];

//policy-2
range = [[attStr string] rangeOfString:@"《隱私政策》"];
[attStr addAttribute:NSFontAttributeName value:font range:range];
[attStr addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithRed:5.0f/255.0f green:164.0f/255.0f blue:255.0f/255.0f alpha:1.0f] range:range];
[attStr addAttribute:NSLinkAttributeName value:kCFPrivacyPolicy_URL range:range];

self.tfPolicy.enabled = YES;
self.tfPolicy.editable = NO;//必須禁止輸入,否則點(diǎn)擊將彈出輸入鍵盤
self.tfPolicy.selectable = YES;// 超連接
self.tfPolicy.allowsEditingTextAttributes = YES;// 超連接
self.tfPolicy.attributedStringValue = attStr;

3. NSTextField光標(biāo)顏色 NSTextFieldCell和NSSecureTextFieldCell垂直居中 附加視圖

- (void)drawRect:(NSRect)dirtyRect {
    
    [super drawRect:dirtyRect];
    
    // Drawing code here.
    /*無(wú)效*/
//    NSView *view = [[NSView alloc] initWithFrame:CGRectMake(0, 0, NSWidth(dirtyRect), NSHeight(dirtyRect))];
//    view.layer.backgroundColor = [NSColor blueColor].CGColor;
//    [self addSubview:view];
}

-(BOOL) becomeFirstResponder {
    
    BOOL res = [super becomeFirstResponder];
    if ( res && self.hadSetInsertionPointColor == NO ) {
        
        NSTextView* textField = (NSTextView*)[self currentEditor];
        if ( [textField respondsToSelector: @selector(setInsertionPointColor:)] ) {
            
            self.hadSetInsertionPointColor = YES;
            [textField setInsertionPointColor:self.insertionPointColor?:self.textColor];
        }
    }
    return res;
}
@end

/**密碼輸入框NSSecureTextField內(nèi)容垂直居中問(wèn)題
 NSSecureTextField-NSSecureTextFieldCell:不垂直居中
 NSSecureTextField-LTSecureTextFieldCell:不垂直居中
 NSTextField-LTSecureTextFieldCell:垂直居中
 
 分類方式:成為第一響應(yīng)者后,才有效;失去第一響應(yīng)者后無(wú)效
 */
@interface LTSecureTextFieldCell : NSSecureTextFieldCell

/**邊界,可以自定義控制視圖等*/
@property (nonatomic, assign) NSEdgeInsets edgeInsets;

@end

@implementation LTTextFieldCell

#pragma mark - 1無(wú)效
//- (NSRect)titleRectForBounds:(NSRect)rect{
//
//    NSRect titleRect = [super titleRectForBounds:rect];
//    CGFloat minimHeight = self.cellSize.height;
//    titleRect.origin.y += (titleRect.size.height - minimHeight)/2;
//    titleRect.size.height = minimHeight;
//    return titleRect;
//}
//
//-(void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView{
//  [super drawWithFrame:cellFrame inView:controlView];
//}
//
//-(void)selectWithFrame:(NSRect)rect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)delegate start:(NSInteger)selStart length:(NSInteger)selLength{
//
//  CGRect titleRect =  [self titleRectForBounds:rect];
//    titleRect.origin.y += 10;//self.oringeY;
//  [super selectWithFrame:titleRect inView:controlView editor:textObj delegate:delegate    start:selStart length:selLength];
// NSLog(@"titleRect = %@",NSStringFromRect(titleRect));
//
//}


#pragma mark - 2
- (NSRect)adjustedFrameToVerticallyCenterText:(NSRect)frame {
    
    // super would normally draw text at the top of the cell
    NSRect rect = CGRectMake(self.edgeInsets.left, self.edgeInsets.top, NSWidth(frame) - self.edgeInsets.left - self.edgeInsets.right, NSHeight(frame) - self.edgeInsets.top - self.edgeInsets.bottom);
    CGFloat fontSize = self.font.boundingRectForFont.size.height;
    NSInteger offset = floor((NSHeight(rect) - ceilf(fontSize))/2) - 2;
    NSRect centeredRect = NSInsetRect(rect, 0, offset);
    return centeredRect;
}

- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)editor delegate:(id)delegate event:(NSEvent *)event {

     [super editWithFrame:[self adjustedFrameToVerticallyCenterText:aRect] inView:controlView editor:editor delegate:delegate event:event];
}

- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)editor delegate:(id)delegate start:(NSInteger)start length:(NSInteger)length {

    [super selectWithFrame:[self adjustedFrameToVerticallyCenterText:aRect] inView:controlView editor:editor delegate:delegate start:start length:length];
}

 - (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)view {

     [super drawInteriorWithFrame:[self adjustedFrameToVerticallyCenterText:frame] inView:view];
}


#pragma mark - 3
/**實(shí)際內(nèi)容區(qū)域:修改了cell的frame,導(dǎo)致在設(shè)置背景色時(shí),部分區(qū)域無(wú)效*/
//- (NSRect)drawingRectForBounds:(NSRect)rect {
//    
//    NSRect rect1 = [super drawingRectForBounds:rect];
//    NSSize size = [self cellSizeForBounds:rect];
//    CGFloat h = rect1.size.height - size.height;
//    if ( h > 0 ) {
//        rect1.size.height = size.height;
//        rect1.origin.y += h * 0.5;
//    }
//    
//    return rect1;
//}

@end

4. 設(shè)置NSTextView失去光標(biāo)

/**設(shè)置NSTextView失去光標(biāo)*/
[self.tvEmail.window makeFirstResponder:nil];
[self.tvSuggest.window makeFirstResponder:nil];

5. 遮罩層MaskView

定制事件傳遞

/**遮罩視圖
 不調(diào)用super方法,阻止了事件的傳遞;
 當(dāng)前:攔截了鼠標(biāo)的右鍵,左鍵,又不會(huì)影響上層的視圖點(diǎn)擊*/
@interface LTMaskView : NSView

/**
 / **在superview中根據(jù)子視圖的identifier匹配LTMaskView,
 設(shè)置LTMaskView的部分事件繼續(xù)傳遞,不被攔截;并且在superview中也可以設(shè)置superview自身事件是否繼續(xù)傳遞、攔截;
 * /
 [self.view.subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
     
     if ( [@"LTMaskView" isEqualToString:obj.identifier] ) {
         LTMaskView *maskView = (LTMaskView *)obj;
         maskView.allowedEventMask = NSEventMaskLeftMouseDown;
     }
 }];
 
 / **與設(shè)置里的自定義鼠標(biāo)主鍵無(wú)關(guān)
 問(wèn)題:present子視圖后,屏蔽了子視圖的動(dòng)作,只有superview的mouseDown事件了
 * /
 [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull aEvent) {

     [self mouseDown:aEvent];
     return nil;/ **事件被攔截,不會(huì)下傳* /
     return aEvent;/ **事件繼續(xù)傳遞* /
 }];
 */
@property (nonatomic, assign) NSEventMask allowedEventMask;

@end

#import "LTMaskView.h"

@implementation LTMaskView

- (instancetype)init {
    
    if ( self = [super init] ) {
        /**tag是只讀屬性,但可以在xib中設(shè)置
         self.tag = 10001;
         */
        self.identifier = NSStringFromClass([self class]);
    
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        self.identifier = NSStringFromClass([self class]);
    }
    return self;
}

- (instancetype)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.identifier = NSStringFromClass([self class]);
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    
}

- (void)mouseDown:(NSEvent *)event {
    
    if ( self.allowedEventMask & NSEventMaskLeftMouseDown ) {
        [super mouseDown:event];
    }
}

- (void)rightMouseDown:(NSEvent *)event {
    
    if ( self.allowedEventMask & NSEventMaskRightMouseDown ) {
        [super rightMouseDown:event];
    }
}

@end

6. 彈框NSAlert

- (void) testForWindow:(NSWindow *) window {
    
    NSAlert *alert = [[NSAlert alloc] init];
    alert.icon = nil;//[NSImage imageNamed:@"icon"];/**nil時(shí),默認(rèn)APPicon*/
    alert.alertStyle = NSAlertStyleWarning;
    [alert addButtonWithTitle:@"確定"];
//    [alert addButtonWithTitle:@"取消"];/**可以注釋*/
//    alert.messageText = @"title";/**可以注釋*/
//    alert.informativeText = @"msg";/**可以注釋*/
    alert.showsSuppressionButton = NO;/**是否展示Don't ask again*/
    
    /**
     方式1
     使用方式1的時(shí)候需要注意的是window不能為nil,
     不要講NSAlert添加在HomeVC的ViewDidLoad中,此時(shí)Window還沒(méi)創(chuàng)建成功。
     */
    [alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
        if (returnCode == NSAlertFirstButtonReturn) {
            NSLog(@"確定");
        } else if (returnCode == NSAlertSecondButtonReturn) {
            NSLog(@"取消");
        } else {
            NSLog(@"else");
        }
    }];
    /*! 方式2
    NSModalResponse response = [alert runModal];
    if (response == NSModalResponseStop) {

    }
    if (response == NSModalResponseAbort) {

    }
    if (response == NSModalResponseContinue) {

    }
    */
}

7. NSView tag

在xib或storyboard中可以設(shè)置tag;但是在代碼里,因?yàn)閠ag為readonly,所以不可以設(shè)置tag。

8. layout 無(wú)效

[self.layer layoutIfNeeded];
[self.layer layoutSublayers];

9. NSBezierPath 圓角 在drawRect中繪制

https://stackoverflow.com/questions/23094140/nsbezierpath-appendbezierpathwitharcfrompoint-wont-draw
/**
 當(dāng)前繪圖的上下文為空,因此無(wú)法繪制。
 即:只有在drawRect函數(shù)內(nèi)部才提供了繪制圖形上下文環(huán)境,
 不能在非drawRect函數(shù)內(nèi)部通過(guò)NSBezierPath或者CGPathRef繪制內(nèi)容
 */
- (void) addArcToProView {
    
    CGSize size = self.proView.bounds.size;
    CGFloat h = size.height;
    CGFloat w = self.tfPro_w.constant / 0.65f;/*重點(diǎn),計(jì)算*/
    NSBezierPath *thePath = [NSBezierPath bezierPath]; // all drawing instruction goes to thePath.
    /*線條*/
    [NSBezierPath setDefaultLineWidth:5.0];
    [[NSColor clearColor] set];/*必須設(shè)置為clearColor,否則會(huì)顯示邊框*/
    [thePath moveToPoint:NSMakePoint(w, h)];
    [thePath lineToPoint:NSMakePoint(0, h)];
    [thePath appendBezierPathWithArcFromPoint:NSMakePoint(0,0)  toPoint:NSMakePoint(h,0) radius:h];
    [thePath lineToPoint:NSMakePoint(w, 0)];
    [thePath lineToPoint:NSMakePoint(w, h)];
    [thePath stroke];
    
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
    maskLayer.frame = CGRectMake(0, 0, w, h);
    maskLayer.path = [[LTCGTool tool] getCGPathFromNSBezierPath:thePath];
    self.proView.layer.mask = maskLayer;
}

#pragma mark - NSBezierPath
/// 獲取NSBezierPath的CGPath
/// 也可以使用分類的方式實(shí)現(xiàn)
/// @param path NSBezierPath
- (CGMutablePathRef)getCGPathFromNSBezierPath:(NSBezierPath *)path {
    
    CGMutablePathRef cgPath = CGPathCreateMutable();
    NSInteger n = [path elementCount];
    
    for (NSInteger i = 0; i < n; i++) {
        NSPoint ps[3];
        switch ([path elementAtIndex:i associatedPoints:ps]) {
            case NSBezierPathElementMoveTo: {
                CGPathMoveToPoint(cgPath, NULL, ps[0].x, ps[0].y);
                break;
            }
            case NSBezierPathElementLineTo: {
                CGPathAddLineToPoint(cgPath, NULL, ps[0].x, ps[0].y);
                break;
            }
            case NSBezierPathElementCurveTo: {
                CGPathAddCurveToPoint(cgPath, NULL, ps[0].x, ps[0].y, ps[1].x, ps[1].y, ps[2].x, ps[2].y);
                break;
            }
            case NSBezierPathElementClosePath: {
                CGPathCloseSubpath(cgPath);
                break;
            }
            default: NSAssert(0, @"Invalid NSBezierPathElement");
        }
    }
    return cgPath;
}

10. NSScrollView

基本用法

//style,overloy會(huì)獨(dú)立出來(lái)scroll的部分,背景透明
_scrollView.scrollerStyle = NSScrollerStyleOverlay;
// 水平和垂直的彈性屬性
_scrollView.horizontalScrollElasticity = NSScrollElasticityNone;
_scrollView.verticalScrollElasticity = NSScrollElasticityNone;
_scrollView.scrollerInsets = NSEdgeInsetsMake(0, 0, 0, -20);//NSEdgeInsets(top:0, left:0, bottom:0, right:-20)
_scrollView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
_scrollView.backgroundColor = [NSColor clearColor];
_scrollView.drawsBackground = NO;
  1. 設(shè)置偏移,也可以給NSScrollView添加extension(Swift)或Category(OC)。
CGFloat pY = 0;
CGFloat h = NSHeight(_scrollView.bounds);
NSView *documentView = self.scrollView.documentView;
if ( NO == documentView.isFlipped ) {
    pY = MAX(NSHeight(_scrollView.bounds), NSHeight(documentView.bounds));
}    
[_scrollView scrollPoint:CGPointMake(0, pY - h + _scrollView.fittingSize.height)];// 設(shè)置無(wú)效
[documentView scrollPoint:CGPointMake(0, pY)];// 粗略值
[documentView scrollPoint:CGPointMake(0, pY - h + _scrollView.fittingSize.height)];// 更為準(zhǔn)確的值
[_scrollView.contentView scrollToPoint:CGPointMake(0, pY - h + _scrollView.fittingSize.height)];// 更為準(zhǔn)確的值
  1. NSScrollView與TitleBar重疊時(shí),top會(huì)有偏移,下列方法清除偏移。
_scrollView.automaticallyAdjustsContentInsets = NO;
//_scrollView.contentInsets = NSEdgeInsetsMake(-44, 0, 0, 0);// 不用
  1. 自定義MYScrollView:禁止滑動(dòng);嵌套,滑動(dòng)事件下傳;
@interface MYScrollView : NSScrollView

@end
@implementation MYScrollView

//- (void)reflectScrolledClipView:(NSClipView *)cView {
// /*禁止滑動(dòng)失敗*/
//}

- (void)scrollWheel:(NSEvent *)event {
    
//    NSLog(@"%@-%s", NSStringFromClass([self class]), __func__);
//    NSLog(@"%s, %@, %@", __func__, self, @(event.phase));
//    [super scrollWheel:event];/*禁止滑動(dòng):重載scrollWheel:,并且不調(diào)用super,無(wú)任何實(shí)現(xiàn)*/
    
    /**嵌套,滑動(dòng)事件下傳:NSScrollView內(nèi)嵌套一個(gè)MYScrollView,可以隨著外側(cè)的NSScrollView一起滾動(dòng)*/
    [self.nextResponder scrollWheel:event];
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容