2010-10-15 10 views
35

Cuando agrego una subvista a UIView, o cuando cambio el tamaño de una subvista existente, esperaría que [view sizeToFit] y [view sizeThatFits] reflejen ese cambio. Sin embargo, mi experiencia es que sizeToFit no hace nada, y sizeThatFits devuelve el mismo valor antes y después del cambio.Tiene problemas para hacer que UIView sizeToFit haga algo significativo

Mi proyecto de prueba tiene una sola vista que contiene un solo botón. Hacer clic en el botón agrega otro botón a la vista y luego llama al sizeToFit en la vista que lo contiene. Los límites de la vista se vuelcan a la consola antes y después de agregar la subvista.

- (void) logSizes { 
NSLog(@"theView.bounds: %@", NSStringFromCGRect(theView.bounds)); 
NSLog(@"theView.sizeThatFits: %@", NSStringFromCGSize([theView sizeThatFits:CGSizeZero])); 
} 

- (void) buttonTouched { 
[self logSizes]; 
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
btn.frame = CGRectMake(10.0f, 100.0f, 400.0f, 600.0f); 
[theView addSubview:btn]; 
[theView sizeToFit]; 
[self performSelector:@selector(logSizes) withObject:nil afterDelay:1.0]; 
} 

Y la salida es:

2010-10-15 15:40:42.359 SizeToFit[14953:207] theView.bounds: {{0, 0}, {322, 240}} 
2010-10-15 15:40:42.387 SizeToFit[14953:207] theView.sizeThatFits: {322, 240} 
2010-10-15 15:40:43.389 SizeToFit[14953:207] theView.bounds: {{0, 0}, {322, 240}} 
2010-10-15 15:40:43.391 SizeToFit[14953:207] theView.sizeThatFits: {322, 240} 

Debo estar perdiendo algo aquí.

Gracias.

Respuesta

48

La documentación es bastante clara al respecto. -sizeToFit prácticamente llama a -sizeThatFits: (probablemente con el tamaño actual de la vista como argumento), y la implementación predeterminada de -sizeThatFits: no hace casi nada (simplemente devuelve su argumento).

Algunas subclases de UIView ignoran -sizeThatFits: para hacer algo más útil (por ejemplo, UILabel). Si desea alguna otra funcionalidad (como cambiar el tamaño de una vista para que se ajuste a sus subvistas), debe subclase UIView y anular -sizeThatFits:.

+1

Gracias Ole. Debería haber leído los documentos más de cerca en lugar de buscar fragmentos de código que dependieran del comportamiento anulado en una subclase particular de UIView. – FishesCycle

+2

Me sorprende que no haya una respuesta aquí que comparta la implementación de dicha anulación. – aleclarson

0

Usted puede hacer algunos como que el uso de IB sola (Xcode 4.5):

  1. Haga clic en la UIView
  2. en el arrastre Tamaño inspector de content hugging al 1 (horizontal y vertical)
  3. arrastre compression resistance a 1000 (para ambos)
  4. debajo de la UIView constraints clic en Width y cambiar priority a 250
  5. hacer lo mismo para Altura
  6. Puede utilizar el UIView 's inset para controlar el relleno de izquierda/derecha/arriba/abajo
0
 self.errorMessageLabel.text = someNewMessage; 

    // We don't know how long the given error message might be, so let's resize the label + containing view accordingly 
    CGFloat heightBeforeResize = self.errorMessageLabel.frame.size.height; 

    [self.errorMessageLabel sizeToFit]; 

    CGFloat differenceInHeightAfterResize = self.errorMessageLabel.frame.size.height - heightBeforeResize; 

    self.errorViewHeightContstraint.constant = kErrorViewHeightConstraintConstant + differenceInHeightAfterResize; 

Esto funcionó para mí.

3

Si no anula UIView, puede usar la extensión.

Swift:

extension UIView { 

    func sizeToFitCustom() { 
     var size = CGSize(width: 0, height: 0) 
     for view in self.subviews { 
      let frame = view.frame 
      let newW = frame.origin.x + frame.width 
      let newH = frame.origin.y + frame.height 
      if newW > size.width { 
       size.width = newW 
      } 
      if newH > size.height { 
       size.height = newH 
      } 
     } 
     self.frame.size = size 
    } 

} 

El mismo código pero 3 veces más rápido:

extension UIView { 
    final func sizeToFitCustom() { 
     var w: CGFloat = 0, 
      h: CGFloat = 0 
     for view in subviews { 
      if view.frame.origin.x + view.frame.width > w { w = view.frame.origin.x + view.frame.width } 
      if view.frame.origin.y + view.frame.height > h { h = view.frame.origin.y + view.frame.height } 
     } 
     frame.size = CGSize(width: w, height: h) 
    } 
} 
Cuestiones relacionadas