macOS 10.12.4下NSButton添加CAGradientLayer后标题不显示的解决方法
macOS 10.12.4按钮渐变背景导致标题不显示的解决办法
问题情况
我写了一段给按钮添加渐变背景的代码,在新版macOS上显示正常,但在macOS 10.12.4中按钮标题无法显示。代码如下:
- (void)setGradient:(NSArray<__kindof NSColor *> *)colorArr StartPoint:(CGPoint)startPoint EndPoint:(CGPoint)endPoint { self.wantsLayer = YES; CAGradientLayer *gradinentlayer = [CAGradientLayer layer]; NSMutableArray *array = [NSMutableArray array]; for (NSColor *color in colorArr) { [array addObject:(id)color.CGColor]; } gradinentlayer.colors = array; gradinentlayer.startPoint = startPoint; gradinentlayer.endPoint = endPoint; gradinentlayer.frame = self.bounds; [self.layer insertSublayer:gradinentlayer atIndex:0]; }
之前试过直接替换按钮的图层:
self.layer = gradinentlayer;
但这会导致按钮原有图层设置全部失效,不符合预期需求,现寻求无需添加子视图的解决方案。
可行方案
方案1:调整图层层级,将内容层移至最上层
旧版macOS中,即使把渐变图层插入到最底层,仍可能遮挡按钮的标题内容图层。可以手动将内容图层移到最上层:
- (void)setGradient:(NSArray<__kindof NSColor *> *)colorArr StartPoint:(CGPoint)startPoint EndPoint:(CGPoint)endPoint { self.wantsLayer = YES; CAGradientLayer *gradinentlayer = [CAGradientLayer layer]; NSMutableArray *array = [NSMutableArray array]; for (NSColor *color in colorArr) { [array addObject:(id)color.CGColor]; } gradinentlayer.colors = array; gradinentlayer.startPoint = startPoint; gradinentlayer.endPoint = endPoint; gradinentlayer.frame = self.bounds; [self.layer insertSublayer:gradinentlayer atIndex:0]; // 将按钮的内容图层移到最前方 if (self.layer.sublayers.count > 1) { CALayer *contentLayer = self.layer.sublayers.lastObject; [self.layer bringSublayerToFront:contentLayer]; } }
方案2:重写按钮的layerClass,直接用渐变层作为底层
这是更稳妥的方案,让按钮的图层本身就是CAGradientLayer,既保留原有图层的所有设置,又不会出现遮挡问题:
// 在自定义按钮类中重写layerClass方法 + (Class)layerClass { return [CAGradientLayer class]; } // 调整setGradient方法 - (void)setGradient:(NSArray<__kindof NSColor *> *)colorArr StartPoint:(CGPoint)startPoint EndPoint:(CGPoint)endPoint { self.wantsLayer = YES; CAGradientLayer *gradientLayer = (CAGradientLayer *)self.layer; NSMutableArray *array = [NSMutableArray array]; for (NSColor *color in colorArr) { [array addObject:(id)color.CGColor]; } gradientLayer.colors = array; gradientLayer.startPoint = startPoint; gradientLayer.endPoint = endPoint; // 无需手动设置frame,图层会跟随按钮bounds自动调整 }
该方案完全遵循AppKit的图层设计逻辑,不会出现图层遮挡问题,同时保留按钮原有的图层属性(如圆角、阴影等),在旧版系统中也能正常运行。
内容的提问来源于stack exchange,提问作者HengChang
相关产品推荐
相关产品推荐

