web-dev-qa-db-fra.com

iOS Core Animation: CALayer apporteSublayerToFront?

Comment apporter un CALayer sublayer à l'avant de toutes les sous-couches, analogue à -[UIView bringSubviewToFront]?

30
ma11hew28

Je suis curieux de savoir pourquoi aucune de ces réponses ne mentionne l'attribut zPosition sur CALayer. Core Animation examine cet attribut pour déterminer l'ordre de rendu des calques. Plus la valeur est élevée, plus elle est proche de l'avant. Ces réponses fonctionnent toutes tant que votre zPosition est 0, mais pour mettre facilement un calque à l'avant, définissez sa valeur zPosition plus élevée que toutes les autres sous-couches.

50
Shaun Budhram

Il s'agit d'une variante de l'implémentation de @ MattDiPasquale qui reflète plus précisément la logique d'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];
}

Remarque: si vous n'utilisez pas ARC, vous souhaiterez peut-être ajouter [layer retain] en haut et [layer release] en bas des deux fonctions pour s'assurer que layer n'est pas détruit accidentellement dans le cas où il a retenu count = 1.

42
ivanzoid

Bon code ici

- (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

Version Swift 4.
Idée selon laquelle la couche elle-même possède les méthodes bringToFront et 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()
4
Vlad

Voici le bon code:

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

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

Créez une catégorie de CALayer comme ceci:

@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

Vous pouvez implémenter cette fonctionnalité dans une catégorie sur CALayer comme ceci:

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

Et pour un accès facile, vous pouvez #import "CALayer+Extension.h" dans le fichier Prefix.pch (en-tête précompilé) de votre projet.

2
Andrei Marincas