我需要浮动自动版式。我发现这是一个很难解决的问题,但我认为可以通过使用此处描述的一些技巧来完成:http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html
也许有人已经尝试解决这样的问题,或者想尝试一下。
所以这是挑战:
浮动效果很好的视图,如果超出了内容宽度,则下降到新行,如下图所示,view1的宽度较大,因此view2下降到新行。 (如果view2宽度变大,也会发生同样的情况)
所有视图按顺序排列,视图可以具有定义的最小宽度,最大宽度应为容器宽度。视图可以在高度上拉伸,但它们始终占据整个内容宽度。
最佳答案
今晚,我努力应对了这一挑战。我在iPhone模拟器中运行了代码;它似乎有效。但是,我没有尝试匹配OP的确切规格,也没有按照链接进行操作的提示。我只是想看看我几个小时后能自行淘汰什么。
在情节提要中,除了固定在根视图两侧的空白黄色滚动视图之外,没有其他任何内容。
灰色的浮动视图位于黄色滚动视图的内部。滚动视图的内容大小的宽度是根视图的宽度;内容大小的高度会缩小和扩展以适应变化的行数。
我唯一不使用“自动布局”的地方是滚动视图的内容视图(在这里,我使用了Apple的所谓“混合方法”)。
每当调用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