Подтвердить что ты не робот

IOS Core Animation: CALayer приноситSublayerToFront?

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

4b9b3361

Ответ 1

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

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

Ответ 2

Это вариация реализации @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 не случайно разрушен в случай имеет значение count = 1.

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

Вы можете реализовать эту функциональность в категории 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 hierarchy.
    if ([layer superlayer] == self)
    {
        [CALayer performWithoutAnimation:^{

            // Add 'layer' to the end of the receiver 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 (предварительно скомпилированный заголовок).

Ответ 7

Создайте категорию 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

Ответ 8

версия 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()