チャットアプリのチャット画面に必要なもの
コロナ禍の中なかなか就職が決まらず暇なので、チャットアプリのチャット画面を作り方を記事にしたいと思います。
チャット画面に最低限必要なものってなんだと思いますか?
今回は僕が勝手に思うチャット画面に最低限必要なもの
で実装していきます。
必要なコンポーネントは以下
tableView: メッセージを一覧表示するのに使います。
MessageCell: プロフィールとかメッセージをまとめます。
profileImageView: プロフィール画像を表示をします。
messageLabel: メッセージの表示をします。
他にも送信時間表示用のlabelとかは?と思われると思いますが、データベースとか使って実際にメッセージの送受信をするわけではないので今回はこれだけにします。
実装
まずはViewControllerの方から
class ViewController: UIViewController {
private let tableView = UITableView()
//メッセージを格納する用の配列
private var messages = [String]()
override func viewDidLoad() {
super.viewDidLoad()
initTableView()
initMessages()
view.addSubview(tableView)
}
//tableViewの設定
private func initTableView() {
tableView.tableFooterView = UIView()
tableView.separatorStyle = .none
tableView.register(MessageCell.self, forCellReuseIdentifier: MessageCell.id)
tableView.delegate = self
tableView.dataSource = self
tableView.frame = view.bounds
}
//messagesにメッセージを追加
private func initMessages() {
messages.append("こんにちは")
messages.append("今日の12時ごろ予定空いてますか?")
messages.append("ひまですね")
messages.append("寿限無(じゅげむ) 寿限無(じゅげむ) 五劫(ごこう)のすりきれ 海砂利(かいじゃり)水魚(すいぎょ)の水行末(すいぎょうまつ) 雲来末(うんらいまつ) 風来末(ふうらいまつ) 食(く)う寝(ね)るところに 住(す)むところ やぶらこうじの ぶらこうじ パイポ パイポ パイポの シューリンガン シューリンガンの グーリンダイ グーリンダイの ポンポコピーのポンポコナの 長久命(ちょうきゅうめい)の長助(ちょうすけ)")
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MessageCell.id, for: indexPath) as! MessageCell
cell.message = messages[indexPath.row]
return cell
}
}
initTableView()
の中を見ていきましょう。
tableFooterView = UIView()
は要素数以上の時に表示される空のcellを消すためです。
separatorStyle = .none
はcellとcellの間の薄い灰色のボーダー線を消します。
register
はカスタムセルを表示するためです。
こちらを参照してください。
コードでカスタムセルを使う時register(_:forCellReuseIdentifier:)関数を入れそびれていた
ViewControllerの中についての説明はこれくらいですかね。
次はカスタムセルを作っていきます。
class MessageCell: UITableViewCell {
static let id = "MessageCell"
public var message: String? {
didSet {
messageLabel.text = message
}
}
private let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = #imageLiteral(resourceName: "image.jpeg")
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = 25
return imageView
}()
private let backView: UIView = {
let view = UIView()
view.backgroundColor = .opaqueSeparator
view.layer.cornerRadius = 20
view.layer.masksToBounds = true
return view
}()
private let messageLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 16)
// labelの行数を指定
label.numberOfLines = 0
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(profileImageView)
addSubview(backView)
backView.addSubview(messageLabel)
setupAutoLayout()
}
private func setupAutoLayout() {
profileImageView.translatesAutoresizingMaskIntoConstraints = false
backView.translatesAutoresizingMaskIntoConstraints = false
messageLabel.translatesAutoresizingMaskIntoConstraints = false
let constraints = [
profileImageView.topAnchor.constraint(equalTo: topAnchor, constant: 10),
profileImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
// profileImageView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
profileImageView.widthAnchor.constraint(equalToConstant: 50),
profileImageView.heightAnchor.constraint(equalToConstant: 50),
backView.topAnchor.constraint(equalTo: profileImageView.topAnchor),
backView.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 5),
backView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
backView.widthAnchor.constraint(lessThanOrEqualToConstant: 250),
messageLabel.topAnchor.constraint(equalTo: backView.topAnchor, constant: 8),
messageLabel.leadingAnchor.constraint(equalTo: backView.leadingAnchor, constant: 8),
messageLabel.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -8),
messageLabel.trailingAnchor.constraint(equalTo: backView.trailingAnchor, constant: -8),
]
NSLayoutConstraint.activate(constraints)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
profileImageView
とbackView
とmessageLabel
の宣言をしています。
クロージャでまとめるといいですね。
backView
はmessageLabel
に直接背景色を指定してしまうと背景と文字の間に余白がなくなって見ずらいのでいい感じに余白を作るために使います。
setupAutoLayout
の中を見ていきましょう。
各view
にtranslatesAutoresizingMaskIntoConstraints = false
という記述があります。
これをしないとautolayout
が使えないことがあるらしいです。
Auto Layoutをコードから使おう
constraints
からはautoLayout
でレイアウトを設定しています。
配列でまとめているのでNSLayoutConstraint.activate()
でまとめて有効にできます。
一部分だけ変更したい場合は
[viewの変数名].topAnchor.constraint(equalTo: topAnchor).isActive = true
でできます。
まとめ
今回は相手側だけになりましたが制約を変更すれば自分の方も作れます。
もっと簡単にできる方法があれば教えてください。
わざわざ自分で実装するのめんどくさいという方はMessageKit
を調べてみてください。
冒頭でも言ったように就職先募集してます。
あー、優しい企業様就職先をください!