简体   繁体   中英

How to put UITableView always in center of UIView?

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 .

  1. Make your tableView's frame sitting in the bounds:

     tableView.frame = self.view.bounds; tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  2. 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); }
  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM