Uitableview Within Uiscrollview Using Autolayout

UITableView within UIScrollView using autolayout

First of all, are those other views (siblings of the table view) strictly above and below the table view? If so, have you considered letting the table view scroll normally, and putting those outside views in the table view's header and footer views? Then you don't need the scroll view.

Second, you may want to read Technical Note TN2154: UIScrollView And Autolayout if you haven't already.

Third, given the information in that tech note, I can think of a few ways to do what you want. The cleanest is probably to create a subclass of UITableView that implements the intrinsicContentSize method. The implementation is trivial:

@implementation MyTableView

- (CGSize)intrinsicContentSize {
[self layoutIfNeeded]; // force my contentSize to be updated immediately
return CGSizeMake(UIViewNoIntrinsicMetric, self.contentSize.height);
}

@end

Then just let auto layout use the table view's intrinsic content size. Create the constraints between the subviews of the scroll view (including the table view) to lay them out, and make sure there are constraints to all four edges of the scroll view.

You probably need to send invalidateIntrinsicContentSize to the table view at appropriate times (when you add or remove rows or change the heights of rows). You could probably just override the appropriate methods in MyTableView to do that. E.g. do [self invalidateIntrinsicContentSize] in -endUpdates, -reloadData, - insertRowsAtIndexPaths:withRowAnimation:, etc.

Here's the result of my testing:

table view with intrinsic content size in scroll view

The scroll view has the light blue background. The red top label and the blue bottom label are siblings of the table view inside the scroll view.

Here's the complete source code for the view controller in my test. There's no xib file.

#import "ViewController.h"
#import "MyTableView.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>

@end

@implementation ViewController

- (void)loadView {
UIView *view = [[UIView alloc] init];
self.view = view;

UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.backgroundColor = [UIColor cyanColor];
[view addSubview:scrollView];

UILabel *topLabel = [[UILabel alloc] init];
topLabel.translatesAutoresizingMaskIntoConstraints = NO;
topLabel.text = @"Top Label";
topLabel.backgroundColor = [UIColor redColor];
[scrollView addSubview:topLabel];

UILabel *bottomLabel = [[UILabel alloc] init];
bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
bottomLabel.text = @"Bottom Label";
bottomLabel.backgroundColor = [UIColor blueColor];
[scrollView addSubview:bottomLabel];

UITableView *tableView = [[MyTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
tableView.translatesAutoresizingMaskIntoConstraints = NO;
tableView.dataSource = self;
tableView.delegate = self;
[scrollView addSubview:tableView];

UILabel *footer = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)];
footer.backgroundColor = [UIColor greenColor];
footer.text = @"Footer";
tableView.tableFooterView = footer;

NSDictionary *views = NSDictionaryOfVariableBindings(
scrollView, topLabel, bottomLabel, tableView);
[view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|[scrollView]|"
options:0 metrics:nil views:views]];
[view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|[scrollView]|"
options:0 metrics:nil views:views]];
[view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|[topLabel][tableView][bottomLabel]|"
options:0 metrics:nil views:views]];
[view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|[topLabel]|"
options:0 metrics:nil views:views]];
[view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-8-[tableView]-8-|"
options:0 metrics:nil views:views]];
[view addConstraint:[NSLayoutConstraint
constraintWithItem:tableView attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:view attribute:NSLayoutAttributeWidth
multiplier:1 constant:-16]];
[view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|[bottomLabel]|"
options:0 metrics:nil views:views]];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
}
cell.textLabel.text = [NSString stringWithFormat:@"Row %d", indexPath.row];
return cell;
}

@end

UITableView inside UIScrollView - Cell not clickable

Do the following thing:

yourView.clipToBounds = true

Now, if UITableView does not appears means your UIView is not same bigger to hold down UITableView.

Make sure that your UIView height is bigger to hold the contents in it and then try to tap on it.

Updated:

If you are using AutoLayout, then do the following thing.

  1. Give the fix height to UIView
  2. Take the outlet of height constraint of UIView
  3. Now, in viewDidLayoutSubviews change the constraint of UIView to UITableView contentSize height.

    self.heightConstraint = self.tableView.contentSize.height

Let me know, if this helps!

Constraining a UITableView within UIScrollView

Give it any height then hook it as outlet then

self.tableHeight.constant = tableView.contentSize.height
self.view.layoutIfNeeded()

UITableView dynamic content size height inside UIScrollView with AutoLayout

The best way to implement this is to scrap the hierarchy that you have now and do the following...

- UIViewController (or UITableViewController)
--- UITableView
----- UIView (as the tableView.tableHeaderView)
------- UILabel
------- UITextField
------- UITextView
----- Rest of the cells for the table view.

The tableView.tableHeaderView is a single (not reusable, concrete) view that is placed at the top of the content of the table view and scrolls with the content of the table view. It doesn't stick to the top of the screen like a section header view does.

This will allow you to delete the scroll view and place everything inside the table view and still doesn't change the methods that you are using to populate the cells as that remains untouched.

I want a UITableView inside of a UIScrollView to extend to the bottom of the UIScrollView and not get cut off by initial screen

I suggest you to use tableView only. You can create your top view in the header of tableView. Doing this there will be no need to maintain the content size of scrollView.

UITableView inside UIScrollView height error

The Apple documentation discourages embedding UITableView within a UIScrollView because it can cause unexpected behaviour:

You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.

This is likely why you are having trouble finding a tutorial. Why do you want to embed a table inside a UIScrollView? It may be more effective to designate rows in the UITableView to act as the content you wish to put in the UIScrollView.

How to make an UIScrollView work with Autolayout and dynamic content?

I finally managed to make this work by following the @Sana answer and also this post to be able to scroll the table view content.

Thanks u all for replying.



Related Topics



Leave a reply



Submit