OSS解説　BRFlabbyTable

#BRFlabbyTable
https://github.com/brocoo/BRFlabbyTable/releases

![687474703a2f2f692e696d6775722e636f6d2f304b6855684d4e2e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/24979/1e22f07c-c891-1edb-5136-80176566c57d.png)

グニャグニャと動くUItableViewです。（リンク先参照）
有機的な動きはSkypeなどでも取り入れられています。
フラットデザインとの相性も良く、見栄えも良いのでこれを自在に使えたらカッコイイですよね！

BRFlabbyTableはApache licenceの元で利用することが出来ます。
折角OSSなので、どのような仕組みなのか見て行きましょう。

今回はReleaseバージョンの1.0.0を利用しています。

##BRMainViewController
まずはサンプルを開いて、メインのViewControllerを見てみましょう。
ここでBRFlabbyTableの使い方や構造がわかります。

まずはdelegateから。
ここで登場するdelegateは３つ
`UITableViewDelegate
UITableViewDataSource
BRFlabbyTableManagerDelegate`
です。

`UITableViewDelegate`と`UITableViewDataSource`は、別段解説する必要は無いと思います。
一点、
`- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath`
でUITableViewCellではなく、BRFlabbyTableViewCellを返している部分に注目してください。
つまり、**BRFlabbyTableは独自のtableViewなのではなく、UITableViewCellによる実装で作られている**ということです。

そして、`BRFlabbyTableManagerDelegate`ですが、ここでは
`- (UIColor *)flabbyTableManager:(BRFlabbyTableManager *)tableManager flabbyColorForIndexPath:(NSIndexPath *)indexPath`
というメソッドだけがあります。
ここでは、特定IndexPathの背景色を返します。

以上でViewController部分の説明は終わりです。
カッコイイ見た目のわりにはUITableViewの使い方を崩さずに実装でき、既存のプロジェクトのUITableView部分を入れ替えれば実装出来るという親和性の高いOSSですね。
次にいよいよソースを見て行きましょう。

##BRflabbyTableのソース
BRflabbyTableの構造は大きく分けて３つ
`BRFlabbyTableManager
BRFlabbyTableViewCell
NSIndexPath+BRFlabbyTable`
です。

##BRFlabbyTableViewCell
このCellはUITableViewCellを継承しており、BRFlabbyTableManagerで指定された通りに描画を行います。
その為、drawrectがソースの大半を占めています。

drawrectでの動作は大きく分けて２つ

```objc
_flabbyHighlightState == BRFlabbyHighlightStateCellTouched || !_isFlabby || (fabs(_verticalVelocity) < 1.0 && _flabbyHighlightState == BRFlabbyHighlightStateNone)
```
の時の動作、これは一言でいえば「静止時の動作」です。
ごちゃごちゃ条件がついていますが、しきい値やタップのステートの条件になります。

ここでしているのは簡単で

```objc
CGContextSetFillColorWithColor(ctx, [_flabbyColor CGColor]);
        CGContextFillRect(ctx, rect);
```
と、ただCellを塗っているだけです。

もう片方は先ほどの条件をelseした部分、つまり指を乗せたりスクロールしたりして有機的な動きをしているのを描画している部分です。

先ほど同様Cell全体を塗った上で３つの分岐をしています。

```objc

switch (_flabbyHighlightState) {
            case BRFlabbyHighlightStateCellAboveTouched:
                controlPointX1 = _touchXLocationInCell + x;
                controlPointX2 = _touchXLocationInCell + x;
                controlPointX3 = x + (w/2 + x) + (w - (w/2 + x))/2;
                controlPointX4 = (x + (w/2 + x))/2;
                controlPointY1 = HIGHLIGHT_Y_CONTROL_POINT;
                controlPointY2 = y+h+controlYOffset;
                CGContextSetFillColorWithColor(ctx, [_flabbyColorAbove CGColor]);
                CGContextFillRect(ctx, CGRectMake(x, y, w, h/2));
                break;
            case BRFlabbyHighlightStateCellBelowTouched:
                controlPointX1 = (x + (w/2 + x))/2;
                controlPointX2 = x + (w/2 + x) + (w - (w/2 + x))/2;
                controlPointX3 = _touchXLocationInCell + x;
                controlPointX4 = _touchXLocationInCell + x;
                controlPointY1 = controlYOffset;
                controlPointY2 = y+h-HIGHLIGHT_Y_CONTROL_POINT;
                CGContextSetFillColorWithColor(ctx, [_flabbyColorBelow CGColor]);
                CGContextFillRect(ctx, CGRectMake(x, y+h/2, w, h/2));
                break;
            default:
                controlPointX1 = (x + (w/2 + x))/2;
                controlPointX2 = x + (w/2 + x) + (w - (w/2 + x))/2;
                controlPointX3 = controlPointX2;
                controlPointX4 = controlPointX1;
                controlPointY1 = y+controlYOffset;
                controlPointY2 = y+h+controlYOffset;
                break;
        }
```

この分岐はそれぞれ
![iOS Simulator Screen Shot May 7, 27 Heisei, 2.57.50 AMのコピー.png](https://qiita-image-store.s3.amazonaws.com/0/24979/75616096-9492-84d8-ec5c-8723f2e3e932.png)
このように指を置いているCellを中心に上下のセルの指定をしています。
ここで勘の良い人は気が付くと思いますが、このBRflabbyTableは目の錯覚が利用されているわけです。

![iOS Simulator Screen Shot May 7, 27 Heisei, 2.57.50 AMのコピー.png](https://qiita-image-store.s3.amazonaws.com/0/24979/ac3d61ab-cfa6-60f5-06fc-695fe1258f28.png)

そう、中央のセルは決して上下にはみ出しているわけではなく上下のセルではみ出した部分を描画しているわけです。
![iOS Simulator Screen Shot May 7, 27 Heisei, 3.11.26 AM.png](https://qiita-image-store.s3.amazonaws.com/0/24979/53027531-4865-836c-135d-599d8dbc395a.png)

黄色と青の部分が上下のセルで描画されている部分です。

スクロールの際は、方向に合わせてすべてBRFlabbyHighlightStateCellAboveTouchedかBRFlabbyHighlightStateCellBelowTouchedにすればよいわけです。

描画はX1,X2,X3,X4とY1,Y2の組み合わせ４点を元に

```objc
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, nil, x, y);
        CGPathAddCurveToPoint(path, nil, controlPointX1, controlPointY1, controlPointX2, controlPointY1, x+w, y);
        CGPathAddLineToPoint(path, nil, x+w, y+h);
        CGPathAddCurveToPoint(path, nil, controlPointX3, controlPointY2, controlPointX4, controlPointY2, x, y+h);
        CGPathCloseSubpath(path);
        CGContextAddPath(ctx, path);
        CGContextSetFillColorWithColor(ctx, [_flabbyColor CGColor]);
        CGContextFillPath(ctx);
        CGPathRelease(path);
```
このようなコードでカーブを描いています。

それぞれの点を描画すると以下のような位置になります。

![iOS Simulator Screen Shot May 7, 27 Heisei, 3.29.16 AM.png](https://qiita-image-store.s3.amazonaws.com/0/24979/b1eb126d-2a04-2a5f-f4f0-a6b5d20563cf.png)

上下のカーブをそれぞれ２点で描いているわけです。

というわけで、BRflabbyTableの有機的なUITableViewCellは目の錯覚を利用しセルがはみ出ているように見せているというトリックでした。
また利用している描画関数もカーブ関数ぐらいなので中身を見てみると以外にも（良い意味で）シンプルな構造だったというわけです。

もっと興味のある方は`BRFlabbyTableManager`や`NSIndexPath+BRFlabbyTable`も覗いてみるといいかもしれません。
`NSIndexPath+BRFlabbyTable`では前と後ろの色を取得する部分、`BRFlabbyTableManager`ではタップ位置を取得する部分を見ることが出来ます。

いじょ