문제

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 http://grab.by/1Wcg

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
도움이 되었습니까?

해결책

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, 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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top