UIScrollView(横)に複数のUITableViewを配置してpagingする。

UIScrollViewをpagingで横スクロールする仕様にしつつ、その上にUITableViewを複数配置してそれぞれを縦にスクロール可能にする方法です。

## １. UIScrollViewのサブクラスを用意します。

```obj-c:PagingScrollView.m
#import <UIKit/UIKit.h>

@interface PagingScrollView : UIScrollView
@end
```

## ２. 大元のViewControllerへPagingScrollViewをAddして、その上にtableViewを並べる。

```obj-c:MasterViewController.m

#define TABLE_WIDTH 106.f

- (void)viewDidAppear:(BOOL)animated {
    
    int numberOfTables = 5;
    
    CGFloat height = self.view.bounds.size.height;
    CGRect tableBounds = CGRectMake(0.0f, 50.f, TABLE_WIDTH, height);
    
    PagingScrollView *scrollView = [[PagingScrollView alloc] initWithFrame:self.view.bounds];
    scrollView.contentSize = CGSizeMake(TABLE_WIDTH * numberOfTables, height);
    scrollView.pagingEnabled = YES;
    scrollView.bounds = tableBounds; // scrollViewのページングをTABLE_WIDTH単位に。
    scrollView.clipsToBounds = NO;   // 非表示になっているtableBounds外を表示。
    scrollView.backgroundColor = [UIColor redColor];
    [self.view addSubview:scrollView];
    
    // ５つのtableViewを横に並べる
    CGRect tableFrame = tableBounds;
    tableFrame.origin.x = 0.f;
    for (int i = 0; i < numberOfTables; i++) {
        
        UITableView *tableView = [[UITableView alloc] initWithFrame:tableFrame style:UITableViewStylePlain];
        switch (i) {
            case 0:
                tableView.backgroundColor = [UIColor yellowColor];
                break;
            case 1:
                tableView.backgroundColor = [UIColor blueColor];
                break;
            case 2:
                tableView.backgroundColor = [UIColor brownColor];
                break;
            case 3:
                tableView.backgroundColor = [UIColor greenColor];
                break;
            case 4:
                tableView.backgroundColor = [UIColor cyanColor];
                break;
            default:
                break;
        }
        [scrollView addSubview:tableView];
        
        tableFrame.origin.x += TABLE_WIDTH;
    }
}
```
※ テスト用として分かりやすいようにbackgroundColorを付けています。

## ３. ScrollViewのタッチ検出範囲を拡張する。

２の状態ではscrollView.boundsで指定した領域(赤い枠)外のタッチイベントに反応出来ないため、PagingScrollViewのhitTestをオーバーライドして対応します。

```obj-c:PagingScrollView.m
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    
    for (UIView *subview in self.subviews) {
        if (CGRectContainsPoint(subview.frame, point))
            return subview;
    }
    return self;
}
```

上のように[(UIView*)hitTest:withEvent:]をオーバーライドすることで、scrollView.bounds外のタッチイベントも受け取れるようになります。
第一引数のpointはtouchPointですので、その位置にサブビュー(この場合はtableView)があればそれを返してあげることでレスボンダチェーンをtableViewに返すことが出来ます。  
  
  
通常、hitTestをオーバーライドする場合は以下のようにする場合が多いようです。

```obj-c:hitTestOverrideView.m

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self)
        return anotherView;
    
    return hitView;
}
```
ですが、今回はscrollViewが全画面表示 + bounds指定されていることが前提ですので[super hitTest:...]を返してしまうとbounds外へのタップ時はhitViewがnilになり、レスポンダは最下部のmasterViewController.viewに移ってしまいます。
そこで前述のように、touchPoint上にtableViewがない場合はself(PagingScrollView)を返してあげることで、tableViewが配置されていない場所へのtouchでも横スクロールが可能になります。

***

#### 補足

以上の形で指定サイズのpagingとtableViewの縦スクロールは可能になります。
ですが、UIScrollViewに一度にたくさんのUITableViewをAddすることはメモリの圧迫に繋がる可能性が高いです。
それを防ぐためには、UITableViewが持つ『Cellの再利用によってメモリ使用量を抑える仕様』をPagingScrollViewでも独自に実装する必要がありますのでご注意を！

また別の実装として、下地のScrollViewを90度回転させた横向きのUITableViewにして、そのcellに-90度回転させた縦向きのUITableViewをAddする。という方法もあります。
この場合は独自のリユース処理を書かなくても良くなるので楽になります。

また、iOS６以降であればUICollectionViewを使うという手も。