12

I added a UITableView as a subview to a custom UIView class I'm working on. However I noticed that whenever I scroll the table it calls my classes layoutSubviews. I'm pretty sure its the UIScrollview that the table is inheriting from which is actually doing this but wanted to know if there is a way to disable this functionality and if not why is it happening? I don't understand why when you scroll a scrollview it needs its superview to layout its subviews.

Code:

@implementation CustomView
- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        self.clipsToBounds = YES;

        UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 15.0, 436.0, 132.0) style:UITableViewStylePlain];
        tableView.dataSource = self;
        tableView.delegate = self;
        tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        tableView.backgroundColor = [UIColor clearColor];
        tableView.showsVerticalScrollIndicator = NO;
        tableView.contentInset = UIEdgeInsetsMake(kRowHeight, 0.0, kRowHeight, 0.0);
        tableView.tag = componentIndex;

        [self addSubview:tableView];
        [tableView release];
    }
    return self;
}
- (void)layoutSubviews {
    // This is called everytime I scroll the tableview
}

@end

marchinram
  • 5,698
  • 5
  • 47
  • 59
  • But tell me why did you do like that?Why are you adding table view to custom view? – Manjunath May 12 '10 at 04:14
  • Long story, I'm creating a custom PickerView which allows multiple selection and is sized differently than a standard one. It basically displays a PickerView background transformed with a clear table on top – marchinram May 12 '10 at 04:29
  • Have you looked at this? The guy seems to have the opposite problem, in that layoutSubviews ISN'T called. He also mentioned a fix, which if you invert it, might work out for you. :) http://stackoverflow.com/questions/728372/when-is-layoutsubviews-called – Kalle Jul 15 '10 at 21:43
  • This behaviour changed in iOS 5 and later -- http://stackoverflow.com/questions/8036457/uiscrollview-layoutsubviews-behavior-changes-in-ios-5 – Nick Dowell Jul 10 '12 at 13:42

3 Answers3

2

Yes, a UIScrollView does call layoutsubviews whenever it scrolls. I could've sworn this was stated in the documentation somewhere, but I guess not.

Anyways, the prevailing idea for this is that a UIScrollView should layout its stuff so that views that currently can't be seen shouldn't be laid out. As users scroll in the scroll view, it should add and remove subviews as necessary. I'm guessing this is what TableViews use to enqueue table cells that get hidden.

Is there any reason why you would care if layoutsubviews gets called or not?

David Liu
  • 9,426
  • 5
  • 40
  • 63
  • no, I was running some code in there that I shouldn't have been running, that makes sense that it lays out subviews when there position change in the scrollview – marchinram Jul 27 '10 at 03:42
  • 2
    You are right, but the real problem is that scrolling a scroll view triggers `layoutSubviews` in its *superview* too, which may be both expensive and unnecessary. I suspect that's a side effect of changing the scroll view's bounds, but it may as well be just a bug. – Costique Jan 14 '11 at 14:55
2

UITableView at least does appear to layout its superview. This behavior can be problematic when you have a layoutSubviews method that might be expensive (e.g. if you call some JavaScript).

The quick fix is add an intermediary subview that prevents the scroll view from laying out your superview. Instead, it will layout the intermediate subview.

This could be somewhat imperfect but it should work for most cases:

Assume UIView * intermediateView is defined as an instance variable:

-(id) initWithFrame:(CGRect)frame
{
    self = [super initWithFrame: frame];
    if (self)
    {
        UIScrollView * theScrollView; // = your scroll view or table view
        intermediateView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
        // Ensures your intermediate view will resize its subviews.
        intermediateView.autoresizesSubviews = YES;

        // Ensure when the intermediate view is resized that the scroll view
        // is given identical height and width.
        theScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
                                         UIViewAutoresizingFlexibleHeight;
        [intermediateView addSubview: theScrollView];

        // Ensure the frame of the scroll view is exactly the bounds of your
        // intermediate view.
        theScrollView.frame = bottomContainerView.bounds;
        [self addSubview: intermediateView];
    }
    return self;
}

-(void) layoutSubviews
{
    intermediateView.frame = CGRectMake(0, 50, 42, 42); // replace with your logic
}
gonzojive
  • 2,206
  • 2
  • 19
  • 16
0

Not sure i understand your issue correctly but when you scroll a tableview it removes the cells not shown from the memory and loads them again when they are scrolled back into visibility (cells are allocated on demand, only the visible ones) , in effect doing what you seem to be describing.

valexa
  • 4,462
  • 32
  • 48