iOS Core Animation: CALayer принесет SublayerToFront? - PullRequest
29 голосов
/ 01 июля 2011

Как мне вывести CALayer sublayer на фронт всех подслоев, аналогично -[UIView bringSubviewToFront]?

Ответы [ 8 ]

48 голосов
/ 22 мая 2014

Мне любопытно, почему ни один из этих ответов не упоминает атрибут zPosition на CALayer.Базовая анимация смотрит на этот атрибут, чтобы выяснить порядок рендеринга слоя.Чем выше значение, тем ближе оно к фронту.Все эти ответы работают до тех пор, пока zPosition равно 0, но чтобы легко вывести слой на передний план, установите его значение zPosition выше, чем у всех других подслоев.

42 голосов
/ 13 июня 2012

Это вариант реализации @ 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 release] внизу обеих функций, чтобы исключить случайное разрушение layer в в случае, если он имеет счет = 1.

7 голосов
/ 19 июля 2012

Правильный код здесь

- (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];
}
4 голосов
/ 18 ноября 2017

Swift 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)
   }
}

Использование:

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()
2 голосов
/ 17 сентября 2015

Создайте категорию 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
2 голосов
/ 06 сентября 2014

Вы можете реализовать эту функцию в категории на CALayer примерно так:

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

И для легкого доступа вы можете #import "CALayer+Extension.h" в файле Prefix.pch (скомпилированный заголовок) вашего проекта.

2 голосов
/ 06 января 2014

Это правильный код:

-(void)bringSubLayerToFront:(CALayer*)layer
{
  [layer.superLayer addSubLayer:layer];
}

-(void)sendSubLayerToBack:(CALayer*)layer
{
  [layer.superlayer insertSublayer:layer atIndex:0];
}
0 голосов
/ 01 июля 2011

Я не думаю, что такие методы существуют, но вы легко можете использовать свой собственный.

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