繁体   English   中英

浮动自动布局iOS / OSX

[英]Floating autolayout iOS/OSX

我需要浮动自动布局。 我发现它很难解决,但我认为可以通过使用这里描述的一些技巧来完成: http//www.objc.io/issue-3/advanced-auto-layout-toolbox.html

也许有人已经尝试解决这样的问题或者想尝试一下。

所以这是挑战: 在此输入图像描述

如果超出内容宽度,则会很好地浮动视图,如下一个图片中的视图1宽度更大,因此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

为了简化,从Covoa文本系统的工作方式中获取灵感。 然后从核心文本和自动布局一点点。

每个视图都将进入一个数组。 他们每个人都没有内容压缩和大量内容拥抱。 每一行都是一个水平方向的NSStackView。 所有这些都将进入具有垂直方向的NSStackView。 那进入滚动视图。

如果视图不适合堆栈视图行1,则重新调整每个堆栈视图行。

它会工作。

如果变得非常大,它可能会很慢。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM