I achieved this with three views controlled by standard protocols and one view controller. In this solution, you only need to link the vertical scroll of the two table view controllers. Horizontal scrolling is provided free of charge through a scroll view wrapping the body of the table view. I use the following UITableViewDelegate function to get locked column headers:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;

Presentation Structure :
- View - The VCs root view - Table View - rowHeadersTable - the locked left hand columns - Scroll View - rowBodyHorizontalScrollView - a container of the table body - Table View - rowBodyVerticalContentTableView - the table body, as wide as it needs to be beyond the frame of the parent scroll view
View controller :
Implemented Protocols:
@interface LockedTableColumnsViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
Setup:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self.rowHeadersTable setDataSource:self]; [self.rowHeadersTable setDelegate:self]; [self.rowBodyVerticalContentTableView setDataSource:self]; [self.rowBodyVerticalContentTableView setDelegate:self]; } -(void)viewDidAppear:(BOOL)animated { // This ensures the scroll view can only scroll horizontally, and adapts to the size of its member content [self.rowBodyHorizontalScrollView setContentSize:self.rowBodyVerticalContentTableView.frame.size]; // Important to do this here rather than viewDidLoad, because we want a final reading on self.rowBodyVerticalContentTableView.frame.size [super viewDidAppear:animated]; } // Do your Table Data Source however you choose
Controlling the vertical scroll binding between rowHeadersTable and rowBodyVerticalContentTableView:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == self.rowBodyVerticalContentTableView) { [self.rowHeadersTable setContentOffset:CGPointMake(self.rowHeadersTable.contentOffset.x, scrollView.contentOffset.y)]; } else if (scrollView == self.rowHeadersTable) { [self.rowBodyVerticalContentTableView setContentOffset:CGPointMake(self.rowBodyVerticalContentTableView.contentOffset.x, scrollView.contentOffset.y)]; } }
NB This will work well for long (i.e. tall) tables, as it uses prototype cells, etc. However, it is not optimized for horizontally intensive row content. The contents of my table body are text and a finite number of columns. If you donโt have such luxury, you can always make the table body in the form of a horizontal stream, but then you have to bind all the offsets of the row collection view (through the visible cells, I think). This whole other animal. Good luck
source share