ios autolayout calayer

Restricción de diseño automático en CALayer IOS



autolayout (7)

De acuerdo con this respuesta, layoutSubviews no se llama en todos los casos necesarios. He encontrado este método de delegado más efectivo:

- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self != nil) { [self.layer addSublayer:self.mySublayer]; } return self; } - (void)layoutSublayersOfLayer:(CALayer*)layer { self.mySublayer.frame = self.bounds; }

Hola, estoy desarrollando una aplicación para iPhone en la que intenté establecer un borde lateral para editar el texto. Hice esto de la siguiente manera:

int borderWidth = 1; CALayer *leftBorder = [CALayer layer]; leftBorder.borderColor = [UIColor whiteColor].CGColor; leftBorder.borderWidth = borderWidth; leftBorder.frame = CGRectMake(0, textField.frame.size.height - borderWidth, textField .frame.size.width, borderWidth); [textField.layer addSublayer:leftBorder];

Pongo algunas restricciones en mi texto de edición en IB para que cuando gire mi dispositivo ajuste el ancho del campo de texto de acuerdo con eso. Mi problema es que ajusta el ancho del texto de edición y no el ancho de CALayer que configuré para mi texto de edición. Así que creo que también tengo que poner algunas restricciones para mi artículo CALayer. Pero no sé cómo hacerlo. ¿Alguien sabe de esto? Necesitas ayuda. Gracias.


Echa un vistazo a esta solución. Use KVO, para la ruta "YourView.bounds" como se indica a continuación.

self.addObserver(self, forKeyPath: "YourView.bounds", options: .New, context: nil)

Luego manéjalo como se indica a continuación.

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) { if (keyPath == "YourView.bounds") { YourLayer.frame = YourView.bounds return } super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) }

Para más información, consulte el siguiente enlace.

https://theswiftdev.com/2015/03/28/auto-layout-with-layers/


Implementé el método layoutSubviews de mi vista personalizada; Dentro de este método, simplemente actualizo el marco de cada subcapa para que coincida con los límites actuales de la capa de mi subvista.

-(void)layoutSubviews{ sublayer1.frame = self.layer.bounds; }


Mi solución cuando creo con borde discontinuo

class DashedBorderView: UIView { let dashedBorder = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } private func commonInit() { //custom initialization dashedBorder.strokeColor = UIColor.red.cgColor dashedBorder.lineDashPattern = [2, 2] dashedBorder.frame = self.bounds dashedBorder.fillColor = nil dashedBorder.cornerRadius = 2 dashedBorder.path = UIBezierPath(rect: self.bounds).cgPath self.layer.addSublayer(dashedBorder) } override func layoutSublayers(of layer: CALayer) { super.layoutSublayers(of: layer) dashedBorder.path = UIBezierPath(rect: self.bounds).cgPath dashedBorder.frame = self.bounds } }


Todo el negocio de autoresizing es específico de vista. las capas no autorizan

Lo que tienes que hacer, en código, es cambiar el tamaño de la capa tú mismo

p.ej

en un viewController que harías

- (void) viewDidLayoutSubviews { [super viewDidLayoutSubviews]; //if you want superclass''s behaviour... // resize your layers based on the view''s new frame self.editViewBorderLayer.frame = self.editView.bounds; }

o en un UIView personalizado que podrías usar

- (void)layoutSubviews { [super layoutSubviews]; //if you want superclass''s behaviour... (and lay outing of children) // resize your layers based on the view''s new frame layer.frame = self.bounds; }


Tuve un problema similar: tuve que establecer el marco de un "CALayer" cuando utilizaba el diseño automático con vistas (en código, no en IB ).

En mi caso, tenía una jerarquía ligeramente complicada, teniendo un controlador de vista dentro de un controlador de vista. Terminé con esta pregunta de SO y examiné el enfoque del uso de viewDidLayoutSubviews . Eso no funcionó. En caso de que su situación sea similar a la mía, esto es lo que encontré ...

Visión general

Quería establecer el marco para el CAGradientLayer de una UIView que estaba posicionando como una subvista dentro de un UIViewController usando restricciones de diseño automático.

Llame a la subvista gradientView y al controlador de vista child_viewController .

child_viewController era un controlador de vista que configuré como un tipo de componente reutilizable. Por lo tanto, la view de child_viewController se estaba componiendo en un controlador de vista principal: llame a ese parent_viewController .

Cuando se llamó a viewDidLayoutSubviews de child_viewController , el frame de gradientView aún no estaba establecido.

(En este punto, recomendaría rociar algunas declaraciones de NSLog para tener una idea de la secuencia de creación de vistas en su jerarquía, etc.)

Así que seguí adelante para intentar usar viewDidAppear . Sin embargo, debido a la naturaleza anidada de child_viewController , encontré que viewDidAppear no estaba siendo llamado.

(Vea esta pregunta SO: viewWillAppear, viewDidAppear no se llama, no se dispara ).

Mi solucion actual

He agregado viewDidAppear en parent_viewController y desde allí llamo viewDidAppear en child_viewController .

Para la carga inicial, necesito viewDidAppear ya que no es hasta que se llama en child_viewController que todas las subvistas tienen sus cuadros establecidos. Entonces puedo establecer el marco para CAGradientLayer ...

He dicho que esta es mi solución actual porque no estoy particularmente contento con ella.

Después de configurar inicialmente el marco de CAGradientLayer , ese marco puede CAGradientLayer ser válido si el diseño cambia, por ejemplo, girando el dispositivo.

Para manejar esto, estoy usando viewDidLayoutSubviews en child_viewController : para mantener el marco de CAGradientLayer dentro de gradientView , correcto.

Funciona pero no se siente bien. (¿Hay alguna manera mejor?)


Swift 3.x KVO Solution (actualización de la respuesta de @ arango_86)

Añadir observador

self.addObserver( self, forKeyPath: "<YOUR_VIEW>.bounds", options: .new, context: nil )

Observar valores

override open func observeValue( forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer? ) { if (keyPath == "<YOUR_VIEW.bounds") { updateDashedShapeLayerFrame() return } super.observeValue( forKeyPath: keyPath, of: object, change: change, context: context ) }