3
votes

I've seen a lot of Stack Overflow threads about this topic (and the iOS 6 release notes), but none have seemed to help me here, or I can't understand them. What I have is a scroll view of size (244, 46) that I want to scroll to twice its width with paging.

My storyboard, showing the list of buttons and the list of constraints, along with the purple constraint that won't delete

In my storyboard I've laid out the scroll view and its subviews (a row of UIButtons) - I set their origins but removed all the constraints saying "Leading space to superview." I replaced them with "Leading space to button" - the horizontal spacing between successive buttons. In code, I set the buttons' translatesAutoresizingMaskIntoConstraints to NO.

I can't get the scroll view to scroll, however. It just bounces to show that there is something on the right side of the scroll view's bounds, just out of reach. Is there anything I'm doing wrong, or something else I need to try to get this to work?

Oh, and there was also a "Trailing space to superview" constraint on the last visible button in Interface Builder (not the last button in the row), and a "Leading space to superview" constraint on the first button that wouldn't stay deleted (see the purple constraint in the image). They annoyingly just popped up in a different spot in the list! Why does this happen, and why isn't the content size being set properly?

Thanks for your time!

1
@rob Thanks for the link, I'm still unclear on some things though- What does "The constraints on the subviews of the scroll view must result in a size to fill" mean? Also, in Pure Auto Layout Approach (I'm doing this in IB) it says "make sure the constraints tie to all edges of the scroll view." What does this mean in IB - pinning the leading and trailing space to superview?architectpianist
You must have constraints between the scroll view and its subviews that force the scroll view to have non-zero size in both dimensions. This size will be the scroll view's content size at runtime; it will not affect the scroll view's frame.rob mayoff
You must have constraints connecting from all four of the scroll view's edges to its subviews to force it to have a non-zero size in both dimensions. If (for example) you don't set any constraints from the scroll view's bottom edge to one of its subviews, then nothing forces the scroll view's content height to be greater than zero.rob mayoff
@rob I think I'm beginning to understand. But I get "Leading Space to Superview Equals 432" and "Trailing Space to Superview Equals -226" when I pin the leading and trailing space to superview, is that correct? And do I need to do this for all the subviews, or just the furthest one from the visible area?architectpianist

1 Answers

0
votes

I took @robmayoff's suggestions and moved my button creation to code, and it miraculously worked. (I'm afraid Auto Layout is still Greek to me, but I somehow managed it.) In case anyone in the future needs to create a scrolling list of buttons, here's a way to do it that doesn't involve setting contentSize explicitly, if a little uglier than IB.

self.toolbarScrollView.translatesAutoresizingMaskIntoConstraints = NO;

NSMutableArray *toolbarItems = [NSMutableArray array];

//Unfortunately, you'll have to set the contentWidth manually - in viewDidLoad
// the frames aren't set yet. 47.0 is the size (38) + margin (9) of one of my
// buttons.
CGFloat x = contentWidth - 47.0;

//This code lets you page the scroll view with more spacing between items on 
//different pages.
int itemCountPerPage = 5;
NSArray *images = @[/*...titles of images...*/];
SEL selectors[10] = {
    //button selectors
};

UIButton *lastButton = nil;

for (int i = 0; i < [images count]; i++)
{
    NSString *imageName = [images objectAtIndex:i];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [button setImage:[UIImage imageNamed:imageName maskedWithColor:[UIColor whiteColor]] forState:UIControlStateNormal];
    button.showsTouchWhenHighlighted = YES;
    if (selectors[i] != NULL)
        [button addTarget:self action:selectors[i] forControlEvents:UIControlEventTouchUpInside];
    [self.toolbarScrollView addSubview:button];
    [toolbarItems addObject:button];

    if (lastButton)
    {
        NSDictionary *dict = NSDictionaryOfVariableBindings(lastButton, button);
        [self.toolbarScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:[lastButton(==38)]-%g-[button(==38)]-%g-|", (i % itemCountPerPage == 0 ? 18.0 : 9.0), x] options:NSLayoutFormatAlignAllCenterY metrics:nil views:dict]];
        [self.toolbarScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-4-[button(==38)]-4-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:dict]];
    }
    else
    {
        NSDictionary *dict = NSDictionaryOfVariableBindings(button);
        [self.toolbarScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-9-[button(==38)]-%g-|", x] options:NSLayoutFormatAlignAllCenterY metrics:nil views:dict]];
        [self.toolbarScrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-4-[button(==38)]-4-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:dict]];          
    }

    x -= (i % itemCountPerPage == itemCountPerPage - 1 ? 56.0 : 47.0);  //Extra space to allow for paging
    lastButton = button;
}

I hope this helps somebody, because it sure caused a lot of trouble for a simple scroll view! Thanks for your help.