I would like to implement a UITableView
in the center of a UIView
. Initially it has only 2 or 3 rows. When user adds more rows, it would extend in vertical direction, while the whole content remains in the center, as shown as below:
Is it possible to do that with UITableView
?
It can be done using UIScrollView's contentOffset
property .
Make your tableView's frame sitting in the bounds:
tableView.frame = self.view.bounds; tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
Declare a method -layoutTableView:
- (void)layoutTableView { CGSize contentSize = tableView.contentSize; CGSize boundsSize = tableView.bounds.size; CGFloat yOffset = 0; if(contentSize.height < boundsSize.height) { yOffset = floorf((boundsSize.height - contentSize.height)/2); } tableView.contentOffset = CGPointMake(0, yOffset); }
When you call [tableView reloadData]
, just call [self layoutTableView]
afterwards.
Another solution is to adjust the content inset of the table view since the content offset solution didn't work for me. Heres the basic idea (inserted into a custom UITableView subclass):
- (void)reloadData {
[super reloadData];
[self centerTableViewContentsIfNeeded];
}
- (void)layoutSubviews {
[super layoutSubviews];
[self centerTableViewContentsIfNeeded];
}
- (void)centerTableViewContentsIfNeeded {
CGFloat totalHeight = CGRectGetHeight(self.bounds);
CGFloat contentHeight = self.contentSize.height;
//If we have less content than our table frame then we can center
BOOL contentCanBeCentered = contentHeight < totalHeight;
if (contentCanBeCentered) {
self.contentInset = UIEdgeInsetsMake(ceil(totalHeight/2.f - contentHeight/2.f), 0, 0, 0);
} else {
self.contentInset = UIEdgeInsetsZero;
}
}
For the Swift-hearted here's a Playground:
import UIKit
import Foundation
import XCPlayground
class CenteredTable: UITableView {
override func reloadData() {
super.reloadData()
centerTableContentsIfNeeded()
}
override func layoutSubviews() {
super.layoutSubviews()
centerTableContentsIfNeeded()
}
func centerTableContentsIfNeeded() {
let totalHeight = CGRectGetHeight(bounds)
let contentHeight = contentSize.height
let contentCanBeCentered = contentHeight < totalHeight
if (contentCanBeCentered) {
contentInset = UIEdgeInsets(top: ceil(totalHeight/2 - contentHeight/2), left: 0, bottom: 0, right: 0);
} else {
contentInset = UIEdgeInsetsZero;
}
}
}
class DataSource: NSObject, UITableViewDataSource {
let items = ["Mr", "Anderson", "Welcome", "Back", "We", "Missed", "You"]
func registerReusableViewsWithTable(tableView: UITableView) {
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = items[indexPath.row]
cell.textLabel?.textAlignment = .Center
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
}
let dataSource = DataSource()
let table = CenteredTable(frame: CGRectMake(0, 0, 300, 800), style: UITableViewStyle.Plain)
table.tableFooterView = UIView(frame: CGRectZero)
let container = UIView(frame: table.frame)
container.addSubview(table)
dataSource.registerReusableViewsWithTable(table)
table.dataSource = dataSource
table.reloadData()
XCPShowView("table", container)
container
If you don't use your headers in the tableview you can dynamically calculate the height of the cells compared to the tableviews bound height.
Kudos to https://stackoverflow.com/a/15026532/1847601
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
CGFloat contentHeight = 0.0;
for (int section = 0; section < [self numberOfSectionsInTableView: tableView]; section++) {
for (int row = 0; row < [self tableView: tableView numberOfRowsInSection: section]; row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: row inSection: section];
contentHeight += [self tableView: tableView heightForRowAtIndexPath: indexPath];
}
}
return (tableView.bounds.size.height - contentHeight)/2;
}
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame: CGRectZero];
view.backgroundColor = [UIColor clearColor];
return view;
}
No need to have that bulky logic. Just use the following line in cellForRowAt()
:
Swift:
tableView.contentInset = UIEdgeInsets(top: (tableView.bounds.height/2 - cell.bounds.height/2), left: 0, bottom: 0, right: 0)
Objective-C:
tableView.contentInset = UIEdgeInsetsMake((tableView.bounds.height/2 - cell.bounds.height/2), 0, 0, 0);
Swift 3
private func hightTableView() {
yourTableView.frame = CGRect(x: 0, y: Int((Int(view.frame.height) - rowHeight * yourArrayData.count) / 2), width: widthTable, height: rowHeight * yourArrayData.count)
}
extension UITableView {
func centeredContent() {
let size = bounds.size
let yOffset = (size.height - contentSize.height)/2
contentInset = yOffset > 0 ? UIEdgeInsets(top: yOffset, left: 0, bottom: 0, right: 0) : .zero
}
}
final class CenteredContentTableView: UITableView {
override func layoutSubviews() {
super.layoutSubviews()
centeredContent()
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.