Autolayout flotante iOS / OSX

Necesito un autoajuste flotante. Me parece que es un problema bastante difícil de resolver, pero creo que se puede hacer utilizando algunos de los consejos descritos aquí: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Tal vez alguien ya haya intentado resolver ese problema o quisiera probarlo.

Entonces aquí está el desafío: introduzca la descripción de la imagen aquí

Vistas bien flotadas que caen a una nueva línea si se superó el ancho del contenido, como en la siguiente vista de la image, el ancho es mayor, de modo que view2 se networkinguce a una nueva línea. (lo mismo sucedería si el ancho de view2 fuera más grande)

introduzca la descripción de la imagen aquí

Todas las vistas vienen en secuencia, las vistas pueden tener definido el ancho mínimo y el máximo ancho debe ser el ancho del contenedor. las vistas pueden estirarse en altura, pero luego siempre tienen un ancho de contenido completo.

Trabajé en este desafío esta noche. Ejecuté el código en el iPhone Simulator; parece funcionar. Sin embargo, no intenté hacer coincidir las especificaciones exactas del OP, ni seguí el enlace a consejos sobre cómo hacer esto. Solo quería ver lo que podría eliminar por mi count en un par de horas.

No hay nada que ver en el guión gráfico excepto una vista de desplazamiento amarilla y vacía fijada a los lados de la vista raíz.

Las vistas flotantes grises están dentro de una vista de desplazamiento amarilla. El ancho del tamaño de contenido de la vista de desplazamiento es el ancho de la vista raíz; la altura del tamaño de contenido se contrae y se expande para acomodar el número variable de filas.

El único lugar en el que no usé Auto Layout fue para la vista de contenido de la vista de desplazamiento (aquí, utilicé el llamado "Método mixto" de Apple).

Los anchos de las celdas flotantes se generan aleatoriamente cuando se invoca viewWillLayoutSubviews. Por lo tanto, todas las celdas flotantes cambian su ancho al girar el dispositivo. Sostuve la altura de todas las celdas flotantes a una constante.

introduzca la descripción de la imagen aquí

introduzca la descripción de la imagen aquí

@interface ViewController () @property (nonatomic, strong) NSMutableArray *floatingViews; @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; @property (nonatomic, strong) UIView *contentView; @end @implementation ViewController #define NUM_OF_VIEWS 18 #define HEIGHT 30.0f #define HORIZONTAL_SPACER 20.0f #define VERTICAL_SPACER 10.0f - (void)viewDidLoad { [super viewDidLoad]; self.contentView = [[UIView alloc] initWithFrame:self.view.bounds]; [self.scrollView addSubview:self.contentView]; self.floatingViews = [[NSMutableArray alloc] init]; for (int i = 0; i < NUM_OF_VIEWS; i++) { UIView *view = [[UIView alloc] init]; view.backgroundColor = [UIColor grayColor]; view.translatesAutoresizingMaskIntoConstraints = NO; [self.floatingViews addObject:view]; [self.contentView addSubview:view]; } } - (void)viewWillLayoutSubviews { [self configureSizeConstraintsForAllViews]; CGFloat superviewWidth = self.view.bounds.size.width; int row = 0; CGFloat leftMargin = 0.0f; for (int i = 0; i < [self.floatingViews count]; i++) { UIView *currentView = self.floatingViews[i]; // is there room for the current view on this row? NSLayoutConstraint *widthConstaint = [self widthConstraintForView:currentView]; CGFloat currentViewWidth = widthConstaint.constant; if ((leftMargin + currentViewWidth) > superviewWidth) { row++; leftMargin = 0.0f; } // position current view [self configureTopConstraintForView:currentView forRow:row]; [self configureLeftConstraintForView:currentView withConstant:leftMargin]; // update leftMargin leftMargin += currentViewWidth + HORIZONTAL_SPACER; } // update size of content view and scroll view's content size CGRect rect = self.contentView.frame; rect.size.width = superviewWidth; rect.size.height = row * (HEIGHT + VERTICAL_SPACER) + HEIGHT; self.contentView.frame = rect; [self.scrollView setContentSize:rect.size]; } - (void)configureSizeConstraintsForAllViews { static BOOL firstTime = YES; if (firstTime) { firstTime = NO; [self configureHeightConstraintsForAllViews]; } for (int i = 0; i < [self.floatingViews count]; i++) { [self configureRandomWidthForView:self.floatingViews[i]]; } } - (void)configureRandomWidthForView:(UIView *)view { CGFloat maxWidth = self.view.bounds.size.width; CGFloat minWidth = 30.0f; CGFloat randomScale = (arc4random() % 101) / 100.0f; // 0.0 - 1.0 CGFloat randomWidth = minWidth + randomScale * (maxWidth - minWidth); assert(randomWidth >= minWidth && randomWidth <= maxWidth); NSLayoutConstraint *widthConstraint = [self widthConstraintForView:view]; if (!widthConstraint) { widthConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; [view addConstraint:widthConstraint]; } widthConstraint.constant = randomWidth; } - (NSLayoutConstraint *)widthConstraintForView:(UIView *)view { NSLayoutConstraint *widthConstraint = nil; for (NSLayoutConstraint *constraint in view.constraints) { if (constraint.firstAttribute == NSLayoutAttributeWidth) { widthConstraint = constraint; break; } } return widthConstraint; } - (NSLayoutConstraint *)topConstraintForView:(UIView *)view { NSLayoutConstraint *topConstraint = nil; for (NSLayoutConstraint *constraint in view.superview.constraints) { if (constraint.firstItem == view || constraint.secondItem == view) { if (constraint.firstAttribute == NSLayoutAttributeTop) { topConstraint = constraint; break; } } } return topConstraint; } - (NSLayoutConstraint *)leftConstraintForView:(UIView *)view { NSLayoutConstraint *leftConstraint = nil; for (NSLayoutConstraint *constraint in view.superview.constraints) { if (constraint.firstItem == view || constraint.secondItem == view) { if (constraint.firstAttribute == NSLayoutAttributeLeft) { leftConstraint = constraint; break; } } } return leftConstraint; } - (void)configureHeightConstraintsForAllViews { assert(self.floatingViews); for (int i = 0; i < [self.floatingViews count]; i++) { UIView *view = self.floatingViews[i]; [view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:HEIGHT]]; } } - (void)configureTopConstraintForView:(UIView *)view forRow:(NSUInteger)row { NSLayoutConstraint *topConstraint = [self topConstraintForView:view]; if (!topConstraint) { topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view.superview attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; [view.superview addConstraint:topConstraint]; } topConstraint.constant = row * (HEIGHT + VERTICAL_SPACER); } - (void)configureLeftConstraintForView:(UIView *)view withConstant:(CGFloat)constant { NSLayoutConstraint *leftConstraint = [self leftConstraintForView:view]; if (!leftConstraint) { leftConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:view.superview attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; [view.superview addConstraint:leftConstraint]; } leftConstraint.constant = constant; } - (BOOL)prefersStatusBarHidden { return YES; } @end 

Para simplificar, inspírate de la forma en que funciona el sistema de text de Covoa. Luego, un poco de Core Text y layout automático.

Cada una de esas vistas entraría en una matriz. Cada uno de ellos no tendría compression de contenido y mucho aarm de contenido. Cada línea sería una NSStackView con orientación horizontal. Todos esos irían en un NSStackView con orientación vertical. Eso en una vista de desplazamiento.

Si una vista no cabe en la línea 1 de vista de stack, reajustará cada línea de vista de stack.

Funcionaria

Puede ser lento si esto se pone realmente grande.