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:
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.
- Give the fix height to
UIView
- Take the outlet of height constraint of
UIView
Now, in
viewDidLayoutSubviews
change the constraint ofUIView
toUITableView
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
Cannot Put a Google Maps Gmsmapview in a Subview of Main Main View
Switch Cameras with Avcapturesession
Uibutton Fails to Properly Register Touch in Bottom Region of iPhone Screen
iPhone Gps in Background Never Resumes After Pause
How to Create Custom Mkannotationview and Custom Annotation Title and Subtitle
When Should I Use the Various Storage Mechanisms in iOS
Uiscreen Mainscreen Bounds Returning Wrong Size
Using Scrollview Programmatically in Swift 3
How to Add Http Headers in Request Globally for iOS in Swift
Ios8 Photos Framework: How to Get the Name(Or Filename) of a Phasset
iPhone App Under Test Crashes After a Few Days
Monotouch/Wcf: How to Consume the Wcf Service Without Svcutil
Swift Countelements() Return Incorrect Value When Count Flag Emoji
Nsurlconnection Get Request Returns -1005, "The Network Connection Was Lost"