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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:36:27  来源:igfitidea点击:

iOS Core Animation: CALayer bringSublayerToFront?

iphoneobjective-cioscore-animationcalayer

提问by ma11hew28

How do I bring a CALayer sublayerto 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 layeris 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 bringToFrontand sendToBackmethods.

斯威夫特 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)
   }
}


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];
}