iOS Core Animation: CALayer принесет SublayerToFront?

29
задан ma11hew28 1 July 2011 в 11:45
поделиться

8 ответов

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

// 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];
}
-4
ответ дан ma11hew28 1 July 2011 в 11:45
поделиться

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

48
ответ дан Shaun Budhram 1 July 2011 в 11:45
поделиться

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

- (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];
}
7
ответ дан comonitos 1 July 2011 в 11:45
поделиться

Версия 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()
4
ответ дан Vlad 1 July 2011 в 11:45
поделиться

Это вариант реализации @ 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.

42
ответ дан ivanzoid 1 July 2011 в 11:45
поделиться

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

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

-(void)sendSubLayerToBack:(CALayer*)layer
{
  [layer.superlayer insertSublayer:layer atIndex:0];
}
2
ответ дан CodenameLambda1 1 July 2011 в 11:45
поделиться

Вы можете реализовать эту функциональность в категории на 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
ответ дан Andrei Marincas 1 July 2011 в 11:45
поделиться

Создайте категорию 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
ответ дан Javier Flores Font 1 July 2011 в 11:45
поделиться