Всем привет! Каждый раз при проектировании и верстке чата у меня возникал вопрос: «А можно ли это как-нибудь упростить?». На следующей неделе мне предстоит верстать большой чат для приложения, поэтому в голове опять начали появляться мысли про облегчение верстки. Немного посидев и потыкав возможности AutoLayout, я нашел способ упростить процесс верстки и дальнейшей работы по максимуму. При решении подобных задач зачастую используют UICollectionView, но в этот раз мы будем использовать UITableView.

Шаг первый: подготовка UITableView


Для начала необходимо создать и правильно настроить UITableView. Я предпочитаю делать это кодом:

tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 44.0
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)

tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

Важным моментом здесь является установка rowHeight и определение estimatedRowHeight.

Шаг второй: создание ячейки


Теперь переходим к самой интересной части – верстанию ячейки! Создайте новый файл, он должен быть сабклассом UITableViewCell, не забудьте поставить галочку на «Also create XIB file». Процесс верстки разобьем на шаги, чтобы было проще.

Перетащите в ячейку новый UIView и поставьте любой backgroundColor, а затем перетащите на этот вью новый UILabel. Теперь в Attributes Inspector для этой UILabel необходимо выставить 0 в поле Lines. Это позволит ячейке иметь несколько строк текста. Должно получиться вот так:

image

Теперь необходимо прицепить края лейбла к краям его супервью с небольшим отступом.

image

А теперь чистая магия! Прицепите левый, верхний и нижний край серой view к соответствующим краям ячейки, затем, отдельным шагом, создайте констрейнт от правого края серой view к правому краю view ячейки. Теперь выберите только что созданный констрейнт и откройте Attributes Inspector для него. В поле Relation необходимо выставить «Greater Than or Equal», а в поле Constant вставить число, например, 60. Этот констрейнт будет ограничивать максимальную ширину «пузырика» сообщения.

image

Переходим к последней части. Создайте констрейнт высоты для «пузырика» сообщения, а затем поставьте «Greater Than or Equal» в Relation и любое значение в поле Constant. Значение Constant будет минимальным размером «пузырика» по высоте, оно зависит от размера шрифта и отступов. Теперь создайте IBOutlet для лейбла и «пузырика» в класс ячейки.

Шаг третий и последний: собрать все вместе


Осталось только заполнить методы UITableViewDataSource и зарегистрировать нашу ячейку:

tableView.register(UINib(nibName: "ExampleCell", bundle: nil), forCellReuseIdentifier: "incomingMessage")

После этого остается только создать и вернуть нашу ячейку:

let cell = tableView.dequeueReusableCell(withIdentifier: "incomingMessage", for: indexPath)
cell.messageLabel.text = "This is a test message"
return cell

Заключение


Вам остается только сверстать такую же ячейку для исходящих сообщений и скруглить углы «пузырика». Согласитесь, способ максимально простой. Пропадает необходимость делать какие-либо вычисления высоты и ширины этого самого «пузырика», нам всего лишь надо делегировать эту работу AutoLayout'у. Вот так выглядит плюс-минус законченный проект:

image

На этом все! Надеюсь, вам понравилось!

Комментарии (8)


  1. infund
    17.04.2019 11:07
    -1

    Публикацию, считаю, можно Tutorial пометить


    1. s_suhanov
      19.04.2019 20:53

      Поддерживаю. Более того: публикация называется "Самый простой способ сделать чат в iOS приложении", а речь в ней о том, как сделать ячейке таблицы динамическую высоту, и чтоб "пузырик" за текстом растягивался. :(


  1. classx
    17.04.2019 11:13

    а можно тоже самое, но только на чистом swift, без XIB?
    есть еще github.com/MessageKit/MessageKit


  1. alexwillrock
    17.04.2019 11:40

    а теперь вопрос со звездочкой — что будет после insert / delete row с положением скролла при 5 — 6 сообщениях ?)


    1. alex_chekel Автор
      18.04.2019 19:04

      Будет трясти, да. Но если сделать кэш значений estimatedRowHeight, то проблема пропадает.


      1. Agranatmark
        18.04.2019 22:28

        Ну можно добавить ещё одну звёздочку =). Что будет, если текст сообщения, можно редактировать? Например в сообщение добавили/удалили 2 строки.


  1. s_suhanov
    19.04.2019 20:31

    Теперь создайте IBOutlet для лейбла и «пузырика» в класс ячейки.

    IBOutlet для лейбла понятно — менять текст. А зачем IBOutlet для "пузырика"?


    1. alex_chekel Автор
      19.04.2019 23:05

      Скруглять углы, менять цвет, например.