views:

605

answers:

3

I have been messing around with a way to justify align a collection of UIView subclasses within a containing view. I am having a little bit of trouble with the algorithm and was hoping someone could help spot my errors. Here is pseudocode of where I am now:

// 1 see how many items there are
int count = [items count];

// 2 figure out how much white space is left in the containing view
float whitespace = [containingView width] - [items totalWidth];

// 3 Figure out the extra left margin to be applied to items[1] through items[count-1]
float margin = whitespace/(count-1);

// 4 Figure out the size of every subcontainer if it was evenly split
float subcontainerWidth = [containingView width]/count;

// 5 Apply the margin, starting at the second item
for (int i = 1; i < [items count]; i++) {
    UIView *item = [items objectAtIndex:i];
    [item setLeftMargin:(margin + i*subcontainerWidth)];
}

The items do not appear to be evenly spaced here. Not even close. Where am I going wrong?

Here is a shot of this algorithm in action: alt text

EDIT: The code above is pseudocode. I added the actual code here but it might not make sense if you are not familiar with the three20 project.

@implementation TTTabStrip (JustifiedBarCategory)
- (CGSize)layoutTabs {
    CGSize size = [super layoutTabs];

    CGPoint contentOffset = _scrollView.contentOffset;
    _scrollView.frame = self.bounds;
    _scrollView.contentSize = CGSizeMake(size.width + kTabMargin, self.height);

    CGFloat contentWidth = size.width + kTabMargin;
    if (contentWidth < _scrollView.size.width) {
        // do the justify logic

        // see how many items there are
        int count = [_tabViews count];

        // 2 figure out how much white space is left
        float whitespace = _scrollView.size.width - contentWidth;

        // 3 increase the margin on those items somehow to reflect.  it should be (whitespace) / count-1
        float margin = whitespace/(count-1);

        // 4 figure out starting point
        float itemWidth = (_scrollView.size.width-kTabMargin)/count;
        // apply the margin
        for (int i = 1; i < [_tabViews count]; i++) {
            TTTab *tab = [_tabViews objectAtIndex:i];
            [tab setLeft:(margin + i*itemWidth)];
        }

    } else {
        // do the normal, scrollbar logic
        _scrollView.contentOffset = contentOffset;
    }
    return size;
}
@end
A: 

I was able to get it to work on my own! I was applying the margin wrong to the elements. The issue is that I needed to apply the margin while considering the previous elements origin and width.

@implementation TTTabStrip (JustifiedBarCategory)
- (CGSize)layoutTabs {
    CGSize size = [super layoutTabs];

    CGPoint contentOffset = _scrollView.contentOffset;
    _scrollView.frame = self.bounds;
    _scrollView.contentSize = CGSizeMake(size.width + kTabMargin, self.height);

    CGFloat contentWidth = size.width + kTabMargin;
    if (contentWidth < _scrollView.size.width) {
        // do the justify logic

        // see how many items there are
        int count = [_tabViews count];

        // 2 figure out how much white space is left
        float whitespace = _scrollView.size.width - contentWidth;

        // 3 increase the margin on those items somehow to reflect.  it should be (whitespace) / count-1
        float margin = whitespace/(count-1);

        // apply the margin
        for (int i = 1; i < [_tabViews count]; i++) {
            // 4 figure out width from the left edge to the right of the 1st element
            float start = [[_tabViews objectAtIndex:i-1] frame].origin.x + [[_tabViews objectAtIndex:i-1] frame].size.width;

            TTTab *tab = [_tabViews objectAtIndex:i];
            [tab setLeft:(start + margin)];
        }
    } else {
        // do the normal, scrollbar logic
        _scrollView.contentOffset = contentOffset;
    }
    return size;
}
@end
coneybeare
A: 

Hey ConeyBeare. I'm looking to integrate this code into TTTabBar.

Where would I put the category? I tried creating a seperate .h with

@interface TTTabBar (JustifiedBarCategory) 
  • (CGSize)layoutTabs;

@end

@implementation TTTabBar (JustifiedBarCategory)

  • (CGSize)layoutTabs { CGSize size = [super layoutTabs];

    CGPoint contentOffset = _scrollView.contentOffset; _scrollView.frame = self.bounds; _scrollView.contentSize = CGSizeMake(size.width + kTabMargin, self.height);

    CGFloat contentWidth = size.width + kTabMargin; if (contentWidth < _scrollView.size.width) { // do the justify logic

    // see how many items there are
    int count = [_tabViews count];
    
    
    // 2 figure out how much white space is left
    float whitespace = _scrollView.size.width - contentWidth;
    
    
    // 3 increase the margin on those items somehow to reflect.  it should be (whitespace) / count-1
    float margin = whitespace/(count-1);
    
    
    // apply the margin
    for (int i = 1; i < [_tabViews count]; i++) {
        // 4 figure out width from the left edge to the right of the 1st element
        float start = [[_tabViews objectAtIndex:i-1] frame].origin.x + [[_tabViews objectAtIndex:i-1] frame].size.width;
    
    
    
    TTTab *tab = [_tabViews objectAtIndex:i];
    [tab setLeft:(start + margin)];
    
    }

    } else { // do the normal, scrollbar logic _scrollView.contentOffset = contentOffset; } return size; } @end

But it comes up with 5 errors stating that it can't find thing referenced in the above method. E.G KTabMargin is undeclared..

Morgz
You're better off posting this as a separate question (and it really isn't an answer to this question). More people are likely to see your question and answer it well if you ask a new question than if you hide a question in the answers to another question.
sth
A: 

coneybeare, thanks for figuring this out, but your solution doesn't really work as expected. It changes the position of tabs on the bar, but the spacing is not right. This seems to work better for me:

#import "TTTabStrip+Justify.h"
#import <Three20UI/UIViewAdditions.h>

// Width returned by [super layoutTabs] is always 10 px more than sum of tab widths
static CGFloat const kContentWidthPadding = 10;
// Adds fixed margin to left of 1st tab, right of last tab
static CGFloat const kHorizontalMargin = 5;

@implementation TTTabStrip (JustifyCategory)

- (CGSize)layoutTabs {
    CGSize size = [(TTTabStrip*)super layoutTabs];

    CGPoint contentOffset = _scrollView.contentOffset;
    _scrollView.frame = self.bounds;
    _scrollView.contentSize = CGSizeMake(size.width, self.height);

    CGFloat contentWidth = size.width - kContentWidthPadding + 2 * kHorizontalMargin;
    if (contentWidth < _scrollView.size.width) {
        // do the justify logic

        // see how many items there are
        int count = [_tabViews count];

        // calculate remaining white space
        float whitespace = _scrollView.size.width - contentWidth;

        // calculate necessary spacing between tabs
        float spacing = whitespace / (count + 1);       

        // apply the spacing
        for (int i = 0; i < count; i++) {
            CGFloat lastTabRight = kHorizontalMargin;

            if (i > 0) {
                TTTab *lastTab = [_tabViews objectAtIndex:i-1];
                lastTabRight = [lastTab right];
            }

            TTTab *tab = [_tabViews objectAtIndex:i];
            [tab setLeft:(lastTabRight + spacing)];
        }

    } else {
        // do the normal, scrollbar logic
        _scrollView.contentOffset = contentOffset;
    }
    return size;
}

@end

Morgz, I also got several compiler errors. I needed to import UIViewAdditions.h and tell it that super is a TTTabStrip.

jm333