iOS 核心动画:CALayer 带来SublayerToFront?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6547527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS Core Animation: CALayer bringSublayerToFront?
提问by ma11hew28
How do I bring a CALayer sublayer
to the front of all sublayers, analogous to -[UIView bringSubviewToFront]
?
我如何将 aCALayer sublayer
带到所有子层的前面,类似于-[UIView bringSubviewToFront]
?
采纳答案by ma11hew28
I don't think such methods exist, but it's easy to roll your own.
我不认为存在这样的方法,但很容易推出自己的方法。
// 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];
}
回答by Shaun Budhram
I'm curious why none of these answers mention the zPosition attribute on CALayer. Core Animation looks at this attribute to figure out layer rendering order. The higher the value, the closer it is to the front. These answers all work as long as your zPosition is 0, but to easily bring a layer to the front, set its zPosition value higher than all other sublayers.
我很好奇为什么这些答案都没有提到 CALayer 上的 zPosition 属性。Core Animation 通过查看此属性来确定图层渲染顺序。值越高,越靠近前面。只要您的 zPosition 为 0,这些答案都有效,但要轻松将图层置于最前面,请将其 zPosition 值设置为高于所有其他子图层。
回答by ivanzoid
This is variation of @MattDiPasquale's implementation which reflects UIView's logic more precisely:
这是@ 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];
}
Note: if you don't use ARC, you may wish to add [layer retain]
at top and [layer release]
at bottom of both functions to make sure layer
is not accidentally destructed in a case it has retain count = 1.
注意:如果您不使用 ARC,您可能希望[layer retain]
在[layer release]
两个函数的顶部和底部添加,以确保layer
在其保留计数 = 1 的情况下不会被意外破坏。
回答by comonitos
Right code here
正确的代码在这里
- (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];
}
回答by Vlad
Swift 4 version.
Idea that layer itself has bringToFront
and sendToBack
methods.
斯威夫特 4 版本。
层本身具有的想法bringToFront
和sendToBack
方法。
#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)
}
}
Usage:
用法:
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()
回答by Andrei Marincas
You can implement this functionality in a category on CALayerlike so:
您可以在CALayer上的类别中实现此功能,如下所示:
CALayer+Extension.h
CALayer+扩展.h
#import <QuartzCore/QuartzCore.h>
typedef void (^ActionsBlock)(void);
@interface CALayer (Extension)
+ (void)performWithoutAnimation:(ActionsBlock)actionsWithoutAnimation;
- (void)bringSublayerToFront:(CALayer *)layer;
@end
CALayer+Extension.m
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
And for easy access you can #import "CALayer+Extension.h"
in your project's Prefix.pch(precompiled header) file.
为了方便访问,您可以#import "CALayer+Extension.h"
在项目的Prefix.pch(预编译头)文件中。
回答by Javier Flores Font
Create a category of CALayer like this:
像这样创建一个 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
回答by CodenameLambda1
This is the correct code:
这是正确的代码:
-(void)bringSubLayerToFront:(CALayer*)layer
{
[layer.superLayer addSubLayer:layer];
}
-(void)sendSubLayerToBack:(CALayer*)layer
{
[layer.superlayer insertSublayer:layer atIndex:0];
}