¿Cómo cambiar el tamaño de una vista personalizada con la ventana con Cocoa Auto Layout?


Tengo una sola ventana con una sola vista personalizada, y quiero que la vista personalizada cambie de tamaño con la ventana para que la llene completamente en cualquier momento. Si escribo:

NSView *contentView = [self.window contentView];
CustomView *customView = [[CustomView alloc] initWithFrame:[contentView bounds]];
[contentView addSubview:customView];
[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeWidth
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeWidth
        multiplier:1
        constant:0]];
[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeHeight
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeHeight
        multiplier:1
        constant:0]];

Entonces la ventana no me permite redimensionarla.
Si añado:

[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

Entonces la vista personalizada no aparece (drawRect: parece que nunca se llama). Probé diferentes maneras (incluyendo el formato visual @"|[customview]|") pero siempre me encuentro con los mismos problemas. Sé que podría hacerse con el sistema de autoresizing más antiguo, con:

[customView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];

Pero quiero usar el sistema Cocoa Auto Layout, y quiero usarlo para casos más complicados (como varias vistas personalizadas que siempre llenan la ventana).

¿Alguien sabe lo que está mal y cómo debo usar el sistema de Diseño automático para obtener el resultado que quiero?

Author: Guillaume, 2011-11-16

4 answers

Con el Diseño automático, hay (al menos) tres formas posibles de restringir una vista para que ocupe toda la vista de contenido de la ventana, redimensionándola cuando sea apropiado.

Restricciones de formato visual con respecto a superview

NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

[contentView addSubview:customView];

NSDictionary *views = NSDictionaryOfVariableBindings(customView);

[contentView addConstraints:
    [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|"
        options:0
        metrics:nil
        views:views]];

[contentView addConstraints:
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|"
    options:0
    metrics:nil
    views:views]];

Restricciones programáticas para los bordes

(esto debería ser equivalente al formato visual anterior)

+ (void)addEdgeConstraint:(NSLayoutAttribute)edge superview:(NSView *)superview subview:(NSView *)subview {
    [superview addConstraint:[NSLayoutConstraint constraintWithItem:subview
        attribute:edge
        relatedBy:NSLayoutRelationEqual
        toItem:superview
        attribute:edge
        multiplier:1
        constant:0]];
}

Y

NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

[contentView addSubview:customView];

[[self class] addEdgeConstraint:NSLayoutAttributeLeft superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeRight superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeTop superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeBottom superview:contentView subview:customView];

Restricción programática para el tamaño

NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

[contentView addSubview:customView];

[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeWidth
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeWidth
        multiplier:1
        constant:0]];
[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeHeight
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeHeight
        multiplier:1
        constant:0]];

El tercer enfoque es el enumerado en el pregunta y puede no funcionar si hay más limitaciones. Por ejemplo, sin:

[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

También se aplica la máscara autoresize original, lo que conduce al comportamiento descrito en la pregunta: la ventana no se redimensiona.

Como se menciona en Regexident, puedes usar:

[_window visualizeConstraints:[contentView constraints]];

Para depurar el Diseño automático. Vale la pena comprobar la salida de la consola también.

 107
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-17 08:47:24

La respuesta de@Bavarious es buena, solo agregaré algunas cosas más.

¡Es muy importante aprender a usar el soporte de depuración integrado! Al igual que con mucho desarrollo, no es realista esperar que siempre obtendrá todo bien en la primera toma. Esta era una preocupación importante con el diseño automático, por lo que pusimos mucho esfuerzo en la depuración. Pasos, brevemente:

  1. Determinar una vista que está en el lugar equivocado. Llamando al método - [NSView _subtreeDescription] desde gdb y / o pasar los argumentos-NSShowAllViews YES puede ayudar a identificar qué vista es incorrecta.
  2. Determine la restricción o restricciones que son incorrectas o faltantes. - [NSLayoutConstraint constraintsAffectingLayoutForOrientation:] ayuda a darle un conjunto más pequeño de restricciones para trabajar. - [NSWindow visualizeConstraints:] puede ayudarle a ver cuáles son esas restricciones y se puede ver a partir de la cual de los que no es algo que desea estar allí. También le mostrará si su diseño es ambiguo (no hay suficientes restricciones).
  3. Determine de dónde vino la restricción incorrecta. La plantilla Cocoa Layout en Instruments es algo así como el instrumento Leaks: te mostrará todos los eventos en el ciclo de vida de una restricción, como dónde se creó, se agregó a una ventana, se modificó, etc. Entonces, una vez que sepa qué restricción es el problema, use el campo de búsqueda en Instrumentos para filtrar hasta solo ver esa restricción, y puede ver retrotracciones para todos los eventos del ciclo de vida y averiguar donde hiciste algo que no querías.

Normalmente el tipo de pregunta que publicarías (¡mis cosas no funcionan!) no será suficiente para que la gente diga lo que está mal, que es una de las razones por las que es importante usar las cosas de depuración. Vea el video de la sesión de WWDC 2011 (gratuito para todos) y los documentos para más información sobre esto.

Buuuuut Realmente puedo decir lo que salió mal esta vez. :- ) Antes de que usted apagó translatesAutoresizingMaskIntoConstraints, usted estaba más limitado que usted quería ser-el ancho y la altura de su vista también se arreglaron, por lo que la ventana no podía cambiar el tamaño. SIN embargo, después de apagarlo, tenía un diseño ambiguo, ¡porque no había fijado su vista en nada! Usted había dicho lo grande que debería ser (igual que el superview), pero no donde se suponía que debía ser.

Ken

Cocoa Frameworks, diseño automático primario autor

 47
Author: Ken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-19 07:00:46

Puede crear restricciones con Anclajes de diseño con un formato muy fácil de leer:

Código Swift2

func fit(childView: UIView, parentView: UIView) {
    childView.translatesAutoresizingMaskIntoConstraints = false
    childView.topAnchor.constraintEqualToAnchor(parentView.topAnchor).active = true
    childView.leadingAnchor.constraintEqualToAnchor(parentView.leadingAnchor).active = true
    childView.trailingAnchor.constraintEqualToAnchor(parentView.trailingAnchor).active = true
    childView.bottomAnchor.constraintEqualToAnchor(parentView.bottomAnchor).active = true
}

Uso:

parrentView.addSubview(childView)
fit(childView, parentView: parrentView)
 6
Author: larva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-23 08:38:17

He descubierto que-drawRect: no será llamado en el caso de que el rectángulo del marco sea 0,0,0,0. Las restricciones indeseables parecen causar que el marco se convierta en 0,0,0,0.

 0
Author: Carmin Politano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-18 22:57:57