UITableViewを使ったらUIがぶっ壊れた


間違っているところやベストプラクティスでない場合がありますので、
その際は是非コメントにお願い致します！


## 前提と問題

Lineトーク画面にそっくりなUIを作成しました

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879369/64ba74cc-fe8c-8344-89e7-863485ee0be5.png" width=30%>
<br>図１：作成したトーク画面のスクリーンショット
<br><br>
上のスクリーンショットでは一見うまくいっていそうだけど、メッセージの送信を行うとレイアウトが崩れてしまいました。
<br><br>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879369/f4fc3c48-8ac2-65fd-bf85-082e4f5f544b.png" width=30%>
<br>図２：メッセージ送信後のトーク画面
<br><br>

この問題について考察していこうと思います。
## 実装方法(問題解決前)

### 作成したcellのもと

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879369/977e6257-be71-4f2f-cf97-e847d2302f22.png" width=60%>
<br>図３：メッセージのセルのもと (赤のViewは本来は透明)<br><br>


特に、中央の３つのViewはStackViewで囲んでおり、Distributionプロパティは Equal Spacingにしてあります。(css でいうところの「justify-content: space-between」)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879369/aa683dc2-7bc6-a499-1a34-76169bd86503.png" width=45%>
<br>図４：UIStackViewで囲まれた３つのUIView


これにより、Lineトーク画面のようなデザインが可能になります。


### 大まかなアルゴリズム
・メッセージ送信時
左のアイコンと右の赤色のViewを消す（isHiddenプロパティをtrueにする）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879369/02515066-7d34-13b0-3d93-053fecf7ea77.png
" width=60%>

・メッセージ受信時
右のアイコンと左の赤色のViewを消す（isHiddenプロパティをtrueにする）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879369/d9ac421f-f00d-f1af-0728-8447a0502c39.png
" width=60%>

### 具体的な実装コード
```swift:TalksViewController
# ...
extension TalksViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return talks?.count ?? 1
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let currentUser = getCurrentUser()
        
        //「セルのもと」からセルオブジェクトを生成
        let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath) as! MessageCell   
        
        // 以下3行は読み飛ばして構わない
        cell.label.text = talks?[indexPath.row].body ?? "トークはありません"
        cell.backgroundColor = UIColor.clear
        cell.selectedBackgroundView = UIView()
       
       # ここから重要
        if talks?[indexPath.row].sender?.username == currentUser?.username {
            // メッセージ受信時
            cell.leftImageView.isHidden = true           
            cell.rightBlank.isHidden = true
        }else if talks?[indexPath.row].receiver?.username == currentUser?.username {
            // メッセージ送信時
            cell.messageBubble.backgroundColor = UIColor(white: 1.0, alpha: 1.0)
            cell.rightImageView.isHidden = true 
            cell.leftBlank.isHidden = true
            
        }
        return cell
    }
}

```

## 解決策
        
### 結論
セルの生成時に、変更した値を明示的に元に戻す必要がある！

うん。わからん。。。

噛み砕いて言うと、

・メッセージ送信時
左のアイコンと右の赤色のViewを消す（isHiddenプロパティをtrueにする）
**右のアイコンと左の赤色のView出現させる（isHiddenプロパティをfalseにする）**

・メッセージ受信時
右のアイコンと左の赤色のViewを消す（isHiddenプロパティをtrueにする）
**左のアイコンと右の赤色のViewを出現させる（isHiddenプロパティをfalseにする）**

このようにする必要がありました。

おそらく、セルの再利用の関係で、このように、明示的に値を設定する必要があるのであろうと思われます。

### コード（修正後）

```swift: TalksViewController.swift
extension TalksViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return talks?.count ?? 1
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let currentUser = getCurrentUser()
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell", for: indexPath) as! MessageCell
        cell.label.text = talks?[indexPath.row].body ?? "トークはありません"
        cell.backgroundColor = UIColor.clear
        cell.selectedBackgroundView = UIView()
        
        if talks?[indexPath.row].sender?.username == currentUser?.username {
            // 書き足したコード(1行)
            cell.messageBubble.backgroundColor = #colorLiteral(red: 0.6209910512, green: 1, blue: 0.592468679, alpha: 1)
            
            cell.leftImageView.isHidden = true
            cell.rightBlank.isHidden = true
            
            //書き足したコード(2行)
            cell.rightImageView.isHidden = false
            cell.leftBlank.isHidden = false
            
        }else if talks?[indexPath.row].receiver?.username == currentUser?.username {
            cell.messageBubble.backgroundColor = UIColor(white: 1.0, alpha: 1.0)
            cell.rightImageView.isHidden = true
            cell.leftBlank.isHidden = true
            
            //書き足したコード(2行)
            cell.leftImageView.isHidden = false
            cell.rightBlank.isHidden = false
        }
        return cell
    }
}

```

## さいごに
以上でUIが綺麗になりました！
セルの再利用について詳しく書きたかったのですが、長くなりそうなので、また別の機会に。少しでも参考になれば嬉しいです。
また、個人的に手書き機能を搭載したアプリを開発したいと考えているのですが、手書き機能の実装経験のある方やおすすめの方法等あれば、教えていただきたいです！！

最後までお読み頂きありがとうございました！！