間違っているところやベストプラクティスでない場合がありますので、
その際は是非コメントにお願い致します!
前提と問題
Lineトーク画面にそっくりなUIを作成しました

図1:作成したトーク画面のスクリーンショット
上のスクリーンショットでは一見うまくいっていそうだけど、メッセージの送信を行うとレイアウトが崩れてしまいました。

図2:メッセージ送信後のトーク画面
この問題について考察していこうと思います。
実装方法(問題解決前)
作成したcellのもと

図3:メッセージのセルのもと (赤のViewは本来は透明)
特に、中央の3つのViewはStackViewで囲んでおり、Distributionプロパティは Equal Spacingにしてあります。(css でいうところの「justify-content: space-between」)

図4:UIStackViewで囲まれた3つのUIView
これにより、Lineトーク画面のようなデザインが可能になります。
大まかなアルゴリズム
・メッセージ送信時
左のアイコンと右の赤色のViewを消す(isHiddenプロパティをtrueにする)
・メッセージ受信時
右のアイコンと左の赤色のViewを消す(isHiddenプロパティをtrueにする)
具体的な実装コード
# ...
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にする)
このようにする必要がありました。
おそらく、セルの再利用の関係で、このように、明示的に値を設定する必要があるのであろうと思われます。
コード(修正後)
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が綺麗になりました!
セルの再利用について詳しく書きたかったのですが、長くなりそうなので、また別の機会に。少しでも参考になれば嬉しいです。
また、個人的に手書き機能を搭載したアプリを開発したいと考えているのですが、手書き機能の実装経験のある方やおすすめの方法等あれば、教えていただきたいです!!
最後までお読み頂きありがとうございました!!