iOS核心animation:CALayer bringSublayerToFront?

如何将CALayer sublayer带到所有子图层的前面,类似于-[UIView bringSubviewToFront]

这是@ MattDiPasquale实现的变体,它更精确地反映了UIView的逻辑:

 - (void) bringSublayerToFront:(CALayer *)layer { [layer removeFromSuperlayer]; [self insertSublayer:layer atIndex:[self.sublayers count]]; } - (void) sendSublayerToBack:(CALayer *)layer { [layer removeFromSuperlayer]; [self insertSublayer:layer atIndex:0]; } 

注意 :如果你不使用ARC,你可能希望在两个函数的顶部添加[layer retain]并且在两个函数的底部添加[layer retain] [layer release] ,以确保在保留count = 1的情况下layer不会被意外地破坏。

我很好奇为什么这些答案都没有提到CALayer上的zPosition属性。 核心animation看这个属性来找出层的渲染顺序。 值越高,越靠前。 只要你的zPosition是0,这些答案都可以工作,但是为了方便地把一个图层放在前面,设置它的zPosition值比所有其他子图层更高。

这里有正确的代码

 - (void)bringSublayerToFront:(CALayer *)layer { CALayer *superlayer = layer.superlayer; [layer removeFromSuperlayer]; [superlayer insertSublayer:layer atIndex:[superlayer.sublayers count]]; } - (void)sendSublayerToBack:(CALayer *)layer { CALayer *superlayer = layer.superlayer; [layer removeFromSuperlayer]; [superlayer insertSublayer:layer atIndex:0]; } 

这是正确的代码:

 -(void)bringSubLayerToFront:(CALayer*)layer { [layer.superLayer addSubLayer:layer]; } -(void)sendSubLayerToBack:(CALayer*)layer { [layer.superlayer insertSublayer:layer atIndex:0]; } 

您可以在CALayer的类别中实现此function,如下所示:

CALayer的+ Extension.h

 #import <QuartzCore/QuartzCore.h> typedef void (^ActionsBlock)(void); @interface CALayer (Extension) + (void)performWithoutAnimation:(ActionsBlock)actionsWithoutAnimation; - (void)bringSublayerToFront:(CALayer *)layer; @end 

CALayer的+ Extension.m

 #import "CALayer+Extension.h" @implementation CALayer (Extension) + (void)performWithoutAnimation:(ActionsBlock)actionsWithoutAnimation { if (actionsWithoutAnimation) { // Wrap actions in a transaction block to avoid implicit animations. [CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; actionsWithoutAnimation(); [CATransaction commit]; } } - (void)bringSublayerToFront:(CALayer *)layer { // Bring to front only if already in this layer's hierarchy. if ([layer superlayer] == self) { [CALayer performWithoutAnimation:^{ // Add 'layer' to the end of the receiver's sublayers array. // If 'layer' already has a superlayer, it will be removed before being added. [self addSublayer:layer]; }]; } } @end 

为了方便访问,您可以在项目的Prefix.pch (预编译头文件)中#import "CALayer+Extension.h"

像这样创build一个CALayer的类别:

 @interface CALayer (Utils) - (void)bringSublayerToFront; @end @implementation CALayer (Utils) - (void)bringSublayerToFront { CGFloat maxZPosition = 0; // The higher the value, the closer it is to the front. By default is 0. for (CALayer *layer in self.superlayer.sublayers) { maxZPosition = (layer.zPosition > maxZPosition) ? layer.zPosition : maxZPosition; } self.zPosition = maxZPosition + 1; } @end 

Swift 4版本。
想法层本身有bringToFrontsendToBack方法。

 #if os(iOS) import UIKit #elseif os(OSX) import AppKit #endif extension CALayer { func bringToFront() { guard let sLayer = superlayer else { return } removeFromSuperlayer() sLayer.insertSublayer(self, at: UInt32(sLayer.sublayers?.count ?? 0)) } func sendToBack() { guard let sLayer = superlayer else { return } removeFromSuperlayer() sLayer.insertSublayer(self, at: 0) } } 

用法:

 let view = NSView(frame: ...) view.wantsLayer = true view.layer?.backgroundColor = NSColor.gray.cgColor let l1 = CALayer(...) let l2 = CALayer(...) view.layer?.addSublayer(l1) view.layer?.addSublayer(l2) l1.bringToFront() 

我不认为这样的方法存在,但很容易推出自己的方法。

 // CALayer+Additions.h @interface CALayer (Additions) - (void)bringSublayerToFront:(CALayer *)layer; - (void)sendSublayerToBack:(CALayer *)layer; @end // CALayer+Additions.m @implementation CALayer (Additions) - (void)bringSublayerToFront:(CALayer *)layer { CALayer *superlayer = self.superlayer; [self removeFromSuperlayer]; [superlayer insertSublayer:gradientLayer atIndex:[self.sublayers count]-1]; } - (void)sendSublayerToBack:(CALayer *)layer { CALayer *superlayer = self.superlayer; [self removeFromSuperlayer]; [superlayer insertSublayer:gradientLayer atIndex:0]; }