2010-04-07 8 views
91

Estoy creando una aplicación que tendrá una pregunta en un UILabel y una respuesta de opción múltiple en UITableView, cada fila muestra una opción múltiple. Las preguntas y respuestas variarán, por lo que necesito que este UITableView sea dinámico en altura.Cambio de tamaño de UITableView para ajustar el contenido

Me gustaría encontrar un sizeToFit alrededor de la mesa. Donde el marco de la tabla se establece a la altura de todo su contenido.

¿Alguien puede aconsejarme sobre cómo puedo lograr esto?

+0

Para cualquiera que desee hacer algo similar en OSX, consulte esta pregunta: http://stackoverflow.com/questions/11322139/get-height-of-content-in -nstableview –

+0

@MiMo hola, ¿puede explicar qué pasa con el enfoque "sizeToFit", por favor? :) – iamdavidlam

+0

_ "Me gustaría encontrar una solución" sizeToFit "alrededor de" _. Entonces, ¿has probado o no has probado el método '- sizeToFit' de UIView? –

Respuesta

129

En realidad, yo mismo encontré la respuesta.

simplemente creo una nueva CGRect para la tableView.frame con el height de table.contentSize.height

que establece la altura de la UITableView a la height de su contenido. Dado que el código modifica la interfaz de usuario, no se olvide de ejecutarlo en el hilo principal:

dispatch_async(dispatch_get_main_queue(), ^{ 
     //This code will run in the main thread: 
     CGRect frame = self.tableView.frame; 
     frame.size.height = self.tableView.contentSize.height; 
     self.tableView.frame = frame; 
    }); 
+0

si esta es la respuesta, márquela como la respuesta – prendio2

+2

Es posible tener problemas con este método. Si tiene una lista grande, es posible que la altura del marco corte algunas de sus celdas. Puede ver que esto sucede si tiene habilitado el rebote y desplácese hasta la parte inferior para ver algunas células rebotar fuera de la vista. – whyoz

+0

¿Dónde exactamente especificaste la altura? ¿Hiciste una llamada para volver a cargar los datos y cambiar el tamaño de los términos posteriores? – James

18

He intentado esto en iOS 7 y funcionó para mí

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    [self.tableView sizeToFit]; 
} 
+2

Esto no parece funcionar para mí – Tumtum

+3

Si su UITableView es dinámico (es decir, cargas de información desde y hacia él sobre la marcha), deberá colocarlo en otro lugar, no en viewDidLoad. Para mí, lo puse en cellForRowAtIndexPath. También tuve que cambiar "tableView" por el nombre de mi propiedad IBOutlet para evitar el viejo error "property tableView no encontrado". – jeremytripp

+0

thx, tenía problemas para cambiar el tamaño de tableview dentro de popover, funcionó – Aleksandr

13

Añadir un observador de la propiedad contentSize en la vista de tabla, y ajustar el tamaño del marco en consecuencia

[your_tableview addObserver:self forKeyPath:@"contentSize" options:0 context:NULL]; 

luego en la devolución de llamada:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
    { 
     CGRect frame = your_tableview.frame; 
     frame.size = your_tableview.contentSize; 
     your_tableview.frame = frame; 
    } 

Espero que esto te ayude.

+2

Debe agregar una cosa más. Debe eliminar el observador para la vista de tabla. Porque se bloqueará si la célula se desasigna. –

1

Mimo's answer y Anooj VM 's answer ambos son impresionantes pero hay un pequeño problema si tiene una lista grande, es posible que la altura del marco corte algunas de sus celdas.

So. He modificado la respuesta un poco:

dispatch_async(dispatch_get_main_queue()) { 
    //This code will run in the main thread: 
    CGFloat newHeight=self.tableView.contentSize.height; 
    CGFloat screenHeightPermissible=(self.view.bounds.size.height-self.tableView.frame.origin.y); 
    if (newHeight>screenHeightPermissible) 
    { 
     //so that table view remains scrollable when 'newHeight' exceeds the screen bounds 
     newHeight=screenHeightPermissible; 
    } 

    CGRect frame = self.tableView.frame; 
    frame.size.height = newHeight; 
    self.tableView.frame = frame; 
} 
-1

Como una extensión de la respuesta de Anooj VM, sugiero lo siguiente para tamaño del contenido de actualización solamente cuando cambia.

Este enfoque también desactivar el desplazamiento más grande correctamente y apoyo listas y rotación. No es necesario dispatch_async porque los cambios de contentSize se envían en el hilo principal.

- (void)viewDidLoad { 
     [super viewDidLoad]; 
     [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:NULL]; 
} 


- (void)resizeTableAccordingToContentSize:(CGSize)newContentSize { 
     CGRect superviewTableFrame = self.tableView.superview.bounds; 
     CGRect tableFrame = self.tableView.frame; 
     BOOL shouldScroll = newContentSize.height > superviewTableFrame.size.height; 
     tableFrame.size = shouldScroll ? superviewTableFrame.size : newContentSize; 
     [UIView animateWithDuration:0.3 
            delay:0 
            options:UIViewAnimationOptionCurveLinear 
            animations:^{ 
          self.tableView.frame = tableFrame; 
     } completion: nil]; 
     self.tableView.scrollEnabled = shouldScroll; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { 
    if ([change[NSKeyValueChangeKindKey] unsignedIntValue] == NSKeyValueChangeSetting && 
     [keyPath isEqualToString:@"contentSize"] && 
     !CGSizeEqualToSize([change[NSKeyValueChangeOldKey] CGSizeValue], [change[NSKeyValueChangeNewKey] CGSizeValue])) { 
     [self resizeTableAccordingToContentSize:[change[NSKeyValueChangeNewKey] CGSizeValue]]; 
    } 
} 

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 
    [self resizeTableAccordingToContentSize:self.tableView.contentSize]; } 

- (void)dealloc { 
    [self.tableView removeObserver:self forKeyPath:@"contentSize"]; 
} 
21

Swift Solución Siga estos pasos

1- Establecer la restricción de altura de la mesa de un guión.

2- Arrastre la restricción de altura del guión gráfico y cree @IBOutlet para ello en el archivo viewController.

@IBOutlet weak var tableHeight: NSLayoutConstraint! 

3- A continuación, puede cambiar la altura de la mesa dynamicaly utilizando este código:

override func viewWillLayoutSubviews() { 
    super.updateViewConstraints() 
    self.tableHeight?.constant = self.table.contentSize.height 
} 
+0

¡Trabajó para mí! thnx – Pushpa

+4

Esta solución siempre cortó la última fila en Xcode 8.3 para mí. –

+0

@Jec C: ¡Tampoco para mí – user30646

7

En caso de que no quieren hacer un seguimiento del tamaño del contenido de la vista de tabla cambia a sí mismo, es posible encontrar este subclase útil.

protocol ContentFittingTableViewDelegate: UITableViewDelegate { 
    func tableViewDidUpdateContentSize(_ tableView: UITableView) 
} 

class ContentFittingTableView: UITableView { 

    override var contentSize: CGSize { 
     didSet { 
      if !constraints.isEmpty { 
       invalidateIntrinsicContentSize() 
      } else { 
       sizeToFit() 
      } 

      if contentSize != oldValue { 
       if let delegate = delegate as? ContentFittingTableViewDelegate { 
        delegate.tableViewDidUpdateContentSize(self) 
       } 
      } 
     } 
    } 

    override var intrinsicContentSize: CGSize { 
     return contentSize 
    } 

    override func sizeThatFits(_ size: CGSize) -> CGSize { 
     return contentSize 
    } 
} 
+1

para SWIFT 3, intrinsicContentSize ha convertido en un var, como 'anular intrinsicContentSize public var: CGSize {// ... someCGSize retorno }' – xaphod

+0

actualizado la respuesta para Swift 3. – xinatanil

+0

no funciona para mí. sigue escondiendo la parte inferior de la tabla – Gulz

1

Hay una forma mucho mejor de hacerlo si utiliza AutoLayout: cambie la restricción que determina la altura. Simplemente calcule el alto de los contenidos de su tabla, luego encuentre la restricción y cámbiela. Aquí hay un ejemplo (suponiendo que la restricción de que determina la altura de su mesa es en realidad una restricción de altura con relación "Igualdad"):

override func viewDidAppear(_ animated: Bool) { 
    super.viewDidAppear(animated) 

    for constraint in tableView.constraints { 
     if constraint.firstItem as? UITableView == tableView { 
      if constraint.firstAttribute == .height { 
       constraint.constant = tableView.contentSize.height 
      } 
     } 
    } 
} 
0

solución Mu para esto en rápida 3: llame a este método en viewDidAppear

func UITableView_Auto_Height(_ t : UITableView) 
{ 
     var frame: CGRect = t.frame; 
     frame.size.height = t.contentSize.height; 
     t.frame = frame;   
} 
1

Swift 3, iOS 10,3

Solución 1: Simplemente ponga self.tableview.sizeToFit() en la función cellForRowAt indexPath. Asegúrese de establecer la altura de la vista de tabla más alta que la que necesita. Esta es una buena solución si no tiene vistas debajo de la tabla vista. Sin embargo, si usted tiene, no se actualizará restricción tableview inferior (Yo no trato de arreglarlo porque se me ocurrió la solución 2)

Ejemplo:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    if let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as? TestCell { 
     cell.configureCell(data: testArray[indexPath.row]) 
     self.postsTableView.sizeToFit() 
     return cell 
    } 

    return UITableViewCell() 
} 

Solución 2: Establezca la restricción de altura de tabla en el guión gráfico y arrástrela al controlador de vista. Si conoce la altura media de la celda y usted sabe cuántos elementos de la matriz contiene, se puede hacer algo como esto:

tableViewHeightConstraint.constant = CGFloat(testArray.count) * 90.0  // Let's say 90 is the average cell height 

* EDIT:

Después de todas las soluciones que intentaron y cada de ellos estaba arreglando algo, pero no completamente, this es la respuesta que explica y soluciona este problema por completo.

0

versión objc de Musa almatri

(void)viewWillLayoutSubviews 
{ 
    [super updateViewConstraints]; 
    CGFloat desiredHeight = self.tableView.contentSize.height; 
    // clamp desired height, if needed, and, in that case, leave scroll Enabled 
    self.tableHeight.constant = desiredHeight; 
    self.tableView.scrollEnabled = NO; 
} 
3

tenía una vista de tabla de desplazamiento dentro de la vista y tuvo que calcular la altura de tableView y cambiar su tamaño en consecuencia. Esos son los pasos que he tomado:

0) agrego un UIView a su scrollView (probablemente funcione sin este paso pero lo hice para evitar cualquier posible conflicto) - esta será una vista de contenedor para su vista de tabla. Si sigue este paso, establezca las fronteras de las vistas a la derecha de las vistas de tabla.

1) crear una subclase de UITableView:

class IntrinsicTableView: UITableView { 

    override var contentSize:CGSize { 
     didSet { 
      self.invalidateIntrinsicContentSize() 
     } 
    } 

    override var intrinsicContentSize: CGSize { 
     self.layoutIfNeeded() 
     return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height) 
    } 

} 

2) clase conjunto de una vista de tabla en Storyboard a IntrinsicTableView: captura de pantalla: http://joxi.ru/a2XEENpsyBWq0A

3) Establecer el heightConstraint a su vista de tabla

4) arrastre el IBoutlet de su tabla hacia su ViewController

5) arrastre el IBoutlet de la restricción de altura de su tabla a su ViewController

6) añadir este método en su ViewController:

override func viewWillLayoutSubviews() { 
     super.updateViewConstraints() 
     self.yourTableViewsHeightConstraint?.constant = self.yourTableView.intrinsicContentSize.height 
    } 

Esperanza esto ayuda

+0

Consulte mi respuesta que se basa en su subclase pero no necesita ninguna configuración de restricciones de altura. – fl034

+0

@ fl034 ¿proporciona un enlace? – Gulz

+0

https://stackoverflow.com/a/48623673/4846592 – fl034

3

solución Swift 4 sin MVA, DispatchQueue, estableciendo restricciones a sí mismo. Esta solución se basa en la respuesta de Gulz.

1) Crear una subclase de UITableView:

class IntrinsicTableView: UITableView { 

    override var contentSize:CGSize { 
     didSet { 
      self.invalidateIntrinsicContentSize() 
     } 
    } 

    override var intrinsicContentSize: CGSize { 
     self.layoutIfNeeded() 
     return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height) 
    } 

} 

2) integrar su tableView en una nueva UIView y establecer la restricción en todos los lados. Establezca la clase personalizada en IntrinsicTableView

3) Debería ver algunos errores, porque Storyboard no toma en cuenta nuestra subclase 'intrinsicContentSize. Solucione esto abriendo el inspector de tamaño y reemplazando el intrinsicContentSize por un valor de marcador de posición. Esto es una anulación para el tiempo de diseño. En tiempo de ejecución utilizará la anulación en nuestra clase IntrinsicTableView

Cuestiones relacionadas