浮动自动布局iOS / OSX
我需要浮动自动布局。 我发现它很难解决,但我认为这可以通过使用这里描述的一些技巧来完成: http : //www.objc.io/issue-3/advanced-auto-layout-toolbox.html
也许有人已经尝试解决这个问题,或想尝试一下。
所以这是挑战:
如果内容宽度超过了,那么浮动的视图会下降到新的行,如下图所示view1的宽度越大,view2就越新。 (如果view2的宽度变大,也会发生)
所有视图按顺序排列,视图可以定义最小宽度,最大宽度应该是容器宽度。 视图可以在高度上伸展,但是它们总是会获得完整的内容宽度。
我今晚在这个挑战上工作。 我在iPhone模拟器中运行代码; 它似乎工作。 但是,我没有尝试去匹配OP的确切规格,也没有按照链接提示如何做到这一点。 我只是想看看我能在几个小时内自行解决。
在故事板中没有任何东西可以看到,除了一个固定在根视图边上的空的黄色滚动视图。
灰色浮动视图在黄色滚动视图内。 滚动视图的内容大小的宽度是根视图的宽度; 内容大小的高度收缩和扩展以适应不同数量的行。
我没有使用自动布局的唯一的地方是滚动视图的内容视图(在这里,我用苹果所谓的“混合方法”)。
只要调用viewWillLayoutSubviews,浮动单元格的宽度就会随机生成。 因此,所有漂浮的单元在设备旋转时改变它们的宽度。 我把所有漂浮的细胞的高度保持不变。
@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
为了简化,从Covoa文本系统的工作方式中获得灵感。 然后从核心文本和自动布局一点点。
每个视图都会放到一个数组中。 他们每个人都没有内容压缩和大量的内容拥抱。 每行都是一个水平方向的NSStackView。 所有这些都将在垂直方向进入NSStackView。 那进入一个滚动视图。
如果一个视图不适合堆栈视图行1,则重新调整每个堆栈视图行。
这将工作。
如果这真的很大,可能会很慢。