ChatLayout is an alternative solution to MessageKit.

Overview

Websummit

ChatLayout

CI Status Release Version Documentation Codecov Codacy Badge Swift Package Manager Carthage compatible Swift 5.2 Platform iOS

Table of contents

About

ChatLayout is an alternative solution to MessageKit. It uses custom UICollectionViewLayout to provide you full control over the presentation as well as all the tools available in UICollectionView.

Features

  • Supports dynamic cells and supplementary view sizes.
  • Animated insertion/deletion/reloading/moving of the items.
  • Keeps content of the last visible item at the top or bottom of the UICollectionView during updates.
  • Provides tools for precise scrolling to the required item.
  • Shipped with generic container views to simplify the custom items implementation.

What ChatLayout doesn't provide (And why it is good)

ChatLayout is the custom UICollectionViewLayout, so:

  • You don't have to extend or override any custom UIViewController or UICollectionView. You need to instantiate them yourself and use them the way you like.

  • ChatLayout does not rely on modified UICollectionViewFlowLayout nor does it rotate your UICollectionView upside-down. This means you can use your views as if they would be regular cells within UICollectionView. You can benefit from using the default UIKit implementations of adjustedContextInsets (and others) because your view controller is a normal view controller without any hacks or tricks.

  • ChatLayout doesn't require you to calculate all the cell sizes before it renders them on the screen. You can fully use auto-layout constraints and rely on the fact that the correct size will be calculated in the runtime. However, ChatLayout as any other UICollectionViewLayout will benefit from you providing the estimated sizes of your cells as it will allow you to get better performance.

  • ChatLayout doesn't enforce you to use any specific data model. You can store your messages and update UICollectionView the way you like. The only thing you need is to respect the natural boundaries that UICollectionView have and correctly implement UICollectionViewDataSource. The Example app uses DifferenceKit to process changes in the data model.

  • ChatLayout doesn't enforce you to use any specific UIViews to create your collection cells. You can create them the way you like. It can be any UICollectionViewCell or UICollectionReusableView. There are some generic UIViews bundled with the library that may help you to build them faster. However, you do not have to use them.

  • ChatLayout doesn't handle the keyboard appearance behavior. You have to implement that yourself from scratch or use the library you are already using in your project. It gives you full control over the keyboard presentation. The only thing you have to do is to update the contentInsets of your UICollectionView.

  • ChatLayout doesn't provide you any input control. You can use any one you like and customise it the way you like. The Example app for instance uses InputBarAccessoryView.

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Installation

ChatLayout is available through CocoaPods, Carthage and SwiftPM. See the Example app for the usage details.

If you are using cocoapods you can install the whole package using pod 'ChatLayout'. If you do not need the additional components provided, you can install only the layout itself using pod 'ChatLayout/Core'

Contributing

ChatLayout is in active development, and we welcome your contributions.

If you’d like to contribute to this repo, please read the contribution guidelines.

Todo

  • Improve the test coverage

About UICollectionViewDiffableDataSource

ChatLayout can process any update commands that you send to your UICollectionView, so you can use UICollectionViewDiffableDataSource as well. But you have to keep in mind that UICollectionViewDiffableDataSource does not support the reloading of cells out of the box if you are relying on the Hashable protocol implementation. It will delete the changed cell and insert the new version of said cell. That may lead to strange animations on the screen, especially when the reloaded cell changes its size. In order to get the best behaviour of the update animation I would strongly recommend you rely on DifferenceKit or a similar library to process the model changes. The Example app does it as well.

About Supplementary Views

It can be tempting and it may look like it is the right way to go, but do not use supplementary views to decorate your messages or groups of them. UICollectionView processes them in a different order: UICollectionViewCells first and only after switches to UICollectionReusableViews. You will most likely face some unexpected behaviour during the animation.

About Texture

ChatLayout can be used together with Texture to improve the auto-layout performance. But keep in mind that it's default wrapper is hardcoded to work exclusively with UICollectionViewFlowLayout. See issue. You will have to implement ChatLayoutDelegate yourself and propagate the node size manually.

About animation

If you see a strange or unexpected animation during the updates, check your data model and the commands you send to the UICollectionView's performBatchUpdates. Especialy if you are using some diffing algorithms like DifferenceKit. It is very possible that you are sending delete/insert commands when you expect to see reload. The easiest way to check it is by adding print("\(updateItems)") into ChatLayout.prepare(forCollectionViewUpdates:) method. ChatLayout doesn't know what you expected to see. It just processes your changes according to the commands it has received.

License

ChatLayout is distributed under the MIT license.

ChatLayout is provided for your use, free-of-charge, on an as-is basis. We make no guarantees, promises or apologies. Caveat developer.

Articles

English:

Russian:

Author

Evgeny Kazaev, [email protected]. Twitter ekazaev

I am happy to answer any questions you may have. Just create a new issue.

Comments
  • keepContentOffsetAtBottomOnBatchUpdates add tolerance range

    keepContentOffsetAtBottomOnBatchUpdates add tolerance range

    Hello @ekazaev 👋 Currently, the layout only scrolls automatically when you have scrolled all the way down. Can you add a configuration for a tolerance range? So that even if you are for example 100pt from the bottom of the Scrollview and a new message comes in, it still scrolls automatically?

    enhancement 
    opened by mschonvogel 19
  • Doesn’t calculate layout when message text edit

    Doesn’t calculate layout when message text edit

    Hi can you fix this case, for example when message has one line text, and I edit this message to to two lined text, it doesn’t make space between edited message and last message

    enhancement question 
    opened by gellertk 17
  • iOS 15 multiple performBatchUpdates causes an animation problem

    iOS 15 multiple performBatchUpdates causes an animation problem

    On the last release of the Chatlayout this issues was address but not really fixed. In-fact in the example all actions are added one after the other. The way we use the library involves several changes at the same time.

    Step to reproduce: Have two different actions in the same operation like: remove a message and add a new one. To simulate that I have updated the sendMessage function in DefaultChatController in line 63 by adding the following code: if !messages.isEmpty { messages.removeLast() }

    So now when you send a message it will delete the last message in the conversation at same time. The StagedChangeset is a collection that now have two operations which involve two performBatchUpdates Sep-30-2021 14-22-31

    I'm opening this pull request to suggest a solution and open the discussion to that. https://github.com/ekazaev/ChatLayout/pull/21

    bug 
    opened by zendesk-benabu 13
  • AssertionFailure

    AssertionFailure

    image

    Hey, first of all, good work with this library! 🙂 I switched from MessageKit.

    I use ChatLayout with RxDataSources and somehow every now and then I'm getting an assertion failure when adding a new message.

    I have not yet looked at the layout in detail and wondered if you might know what the problem could be?

    bug 
    opened by mschonvogel 11
  • Xcode version  13.2 build issue

    Xcode version 13.2 build issue

    Hi bro, I use Xcode 13.2 as a daily basis IDE. however, I met a compile error segmentation fault 11 for some files such as StateController line 675 columns 13. I've also realized that there is no Xcode backward compatibility. I've wondered so much as well.

    Do you have any clue what's wrong with it?

    question 
    opened by farshadmb 10
  • Keeping CollectionView at bottom when inserting any new message.

    Keeping CollectionView at bottom when inserting any new message.

    First off, Hats off for this amazing layout, I have always struggled with chat layouts due to weird bugs and unknown issues that happen during the development, but this layout has made my life 100x easier.

    What I'm trying to achieve is to always keep the CollectionView at bottom when a new message is inserted.

    I tried this code snippet

                    self.collectionView.reload(using: stagedChangeSet) { messages in
                        self.messages = messages
                        self.collectionView.scrollToItem(at: IndexPath(item: messages.count - 1, section: 0), at: .bottom, animated: true)
                    }
    

    But it looks like it's not working and throwing this error

    [UICollectionView] Warning: Invalid IndexPath <NSIndexPath: 0x9ece669de5d637ba> {length = 2, path = 0 - 6} specified - will use a contentOffset of {0,0} as a fallback value. <UICollectionView: 0x7fb7fd072400; frame = (0 0; 375 529); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x600001007720>; layer = <CALayer: 0x6000018633a0>; contentOffset: {0, 0}; contentSize: {374.99990000000003, 1412}; adjustedContentInset: {0, 0, 0, 0}; layout: <ChatLayout: 0x7fb7fcc25140>; dataSource: <ChatBotViewController: 0x7fb7faf35b20>>
    

    Any idea what I'm doing wrong ?

    question 
    opened by tareksabry1337 10
  • Translation button break the UI

    Translation button break the UI

    On iOS15 Apple added a new Translate button in the uiMenuController. Step to reproduce: Select the text from the input bar and click to translate, then close the bottom sheet Result: The ChatViewController will scroll up and the input bar will be removed: translation

    bug 
    opened by zendesk-benabu 9
  • Huge bottom space and weird behavior for 1.1.11

    Huge bottom space and weird behavior for 1.1.11

    Hi, some issues popped up with your lib. Up until 1.1.10 my app behaved fine, but as soon as I've upgraded ChatLayout to 1.1.11, things got flaky. When entering a chat room, a huge chunk of empty space without any chat message cells is shown. When looking into layout inspector, no cells show up within the collectionView. When scrolling up, some chat message cells appear, but when scrolling back down they start to disappear again. I first thought it is some autolayout issue (which it could still be), but it worked pre 1.1.11, so I thought I want to ask you here if you know what the issue could be.

    trim 99C16C45-89F9-4ABF-98F9-6EC81DEFBCE1

    Thank you, and it's a really cool library you have here! Andreas

    bug 
    opened by aplr 8
  • Section Headers/Footers are not animated along the cells (insert/update/delete)

    Section Headers/Footers are not animated along the cells (insert/update/delete)

    Hi,

    Im trying to integrate your ChatLayout library into an iOS project. At first, let me thank you for awesome job you did here. Currently Im trying to structure the chat the way that: Every message in the chat is represented as a single section in the collection view and read indicator is always shown under the latest message as a footer of the last message (section).

    1. Self-sizing/autolayout issue:

    Im using self-sizing cells, but I'm not sure if Im setting the correct value for estimatedSize. The self-sizing in this library works for any non-zero values, so eg setting the estimatedSize like following

    collectionLayout.settings.estimatedItemSize = CGSize(width: 1, height: 1)
    

    will display the cells, but at the same time will result in broken autolayout constraints

    "<NSLayoutConstraint:0x600001d0e990 'UIView-Encapsulated-Layout-Height' UIView:0x7fdcbc40d8e0.height == 1   (active)>"
    

    I wanted to use some general purpose estimatedSize for self-sizing cells, similar to the flow layout one:

    UICollectionViewFlowLayout.automaticSize
    

    but later realised since this is a custom collection view layout, this value is not declared.

    Setting the estimated size to a concrete value, e.g. CGSize(width: 100, height: 30) will result in a treatment, where the cell's frame won't properly adjust as the content of the cell changes. If you have any guidance here, Id really appreciate your help

    2. Header/Footer are not part of the animation transaction In my app, I want to treat the read indicator as a standalone item == not added as a subview in the cell, to gain better abstraction and to not pollute the cell with the standalone item.

    Im including a sample SwiftUI app that leverages the ChatLayout - aim of this app is to showcase the issue #1 & #2. ChatApp.zip

    Any help highly appreciated! Thanks!

    Screen-Recording-2020-10-31-at-20 05 05

    question 
    opened by bielikb 8
  • CollectionView does not scroll to last item when not visible item

    CollectionView does not scroll to last item when not visible item

    Expected behaviour: When a user sends a message and taps on the send button, the should be a scroll to the last item in the CollectionView.

    Actual behaviour: When a user sends a message and taps on the send button, the CollectionView will scroll to show the just top of the last item.

    It appears to be taking the estimated item size instead of the actual size of the new cell that has just been sent by the end user. The cell is added to the view and can be seen once you manually scroll to the bottom. Example: when we increased the estimated item height to 100, the scrolling was correct, but only for smaller messages. If it was a bigger message, it would be cut off after 100 height.

    Something to note is that the above behaviour occurs when animation = true when scrolling i.e. self?.collectionView.setContentOffset(contentOffsetAtBottom, animated: true). When animation = false the CollectionView will scroll to the correct position.

    Reproduction steps:

    1. Open conversation
    2. Have at least enough messages where you can scroll up and not see the latest message
    3. Send a message while you are scrolled and can’t see the latest message
    4. See how it scrolls only to the top of the latest message not to the cell itself.

    Note: scrollToBottom() is not currently working in the Example app provided

    enhancement question 
    opened by deehegarty 7
  • Cannot installed with Carthage

    Cannot installed with Carthage

    Hi, team. I'm trying to integrate the xcframework of this project via Carthage but it fails on command line compilation.

    Please help me with this issue.

    help wanted 
    opened by tangzzz-fan 6
Releases(1.2.15)
Owner
Eugene Kazaev
Eugene Kazaev
Schedule timing task in Swift using a fluent API. (A friendly alternative to Timer)

Schedule(简体中文) Schedule is a timing tasks scheduler written in Swift. It allows you run timing tasks with elegant and intuitive syntax. Features Elega

Luo Xiu 1.8k Jan 7, 2023
MZFormSheetPresentationController provides an alternative to the native iOS UIModalPresentationFormSheet, adding support for iPhone and additional opportunities to setup UIPresentationController size and feel form sheet.

MZFormSheetPresentationController MZFormSheetPresentationController provides an alternative to the native iOS UIModalPresentationFormSheet, adding sup

Michał Zaborowski 979 Nov 17, 2022
🔄 GravitySlider is a beautiful alternative to the standard UICollectionView flow layout.

GravitySliderFlowLayout Made by Applikey Solutions Find this project on Dribbble Table of Contents Purpose Supported OS & SDK Versions Installation Us

Applikey Solutions 958 Dec 23, 2022
A modern AppList alternative

AltList A modern AppList alternative The main focus of this dependency is to be an easy to use and easy to customize framework to handle per app prefe

Lars Fröder 59 Jan 2, 2023
An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations and programmatic navigation.

swiftui-navigation-stack An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations

Matteo 753 Jan 2, 2023
Schedule timing task in Swift using a fluent API. (A friendly alternative to Timer)

Schedule(简体中文) Schedule is a timing tasks scheduler written in Swift. It allows you run timing tasks with elegant and intuitive syntax. Features Elega

Luo Xiu 1.8k Dec 21, 2022
🔸 A customizable alternative to UIPickerView in Swift.

PickerView PickerView is an easy to use and customize alternative to UIPickerView written in Swift. It was developed to provide a highly customizable

Filipe Alvarenga 488 Dec 21, 2022
iOS / Objective C: an extremely simple UIAlertView alternative

RKDropdownAlert an extremely simple (and customizeable) alert alternative based on Facebook's app Slingshot, and inspiration from SVProgressHUD (yes,

Richard Kim 1.5k Nov 20, 2022
A WeChat alternative. Written in Swift 5.

TSWeChat - A WeChat alternative, updated to Swift 5. 中文说明 Requirements Cocoapods 1.2.0 + iOS 10.0+ / Mac OS X 10.9+ Xcode 10.0+ Features Send your ric

Hilen Lai 3.7k Dec 31, 2022
An alternative to Core Data for people who like having direct SQL access.

FCModel 2 An alternative to Core Data for people who like having direct SQL access. By Marco Arment. See the LICENSE file for license info (it's the M

null 1.7k Dec 28, 2022
An alternative app store for non-jailbroken iOS devices

AltStore AltStore is an alternative app store for non-jailbroken iOS devices. AltStore is an iOS application that allows you to sideload other apps (.

null 1 Dec 9, 2021
The alternative last.fm client for iOS made with SwiftUI

first.fm - The alternative last.fm client for iOS (it's actually not available on the App Store... yet) Features Your profile (top artists, tracks and

Stanislas 22 Aug 22, 2022
An alternative to UIStackView for common Auto Layout patterns.

StackLayout StackLayout builds on Auto Layout to make some of the most common layouts easier to manage. It creates the constraints that you need and a

Bridger Maxwell 76 Jun 29, 2022
Working alternative to Xcode previews.

SwiftUIPlaygrounds! A shell project you can use to iterate over SwiftUI interfaces using the HotReloading project. Instead of a "preview" the interfac

John Holdsworth 9 Dec 21, 2021
An elegant alternative to the UIStepper written in Swift

An elegant alternative to the UIStepper in Swift with a thumb slider addition to control the value update with more flexibility. Usage let stepper = S

Yannick Loriot 426 Sep 22, 2022
Nicely animated flat design switch alternative to UISwitch

AIFlatSwitch A smooth, nice looking and IBDesignable flat design switch for iOS. Can be used instead of UISwitch. Inspired by Creativedash's Dribbble

null 963 Jan 5, 2023
📱 A minimal tab bar alternative

MiniTabBar A clean simple alternative to the UITabBar. Only shows the title when being tapped on. Gives the app a way cleaner look :) Requirements iOS

Dylan Marriott 155 Dec 20, 2022
● ○ ○ ○ A nice, animated UIPageControl alternative.

Page Control Installation Usage Example import UIKit import PageControl class ViewController: UIViewController, UIScrollViewDelegate { @IBOu

Kasper Lahti 113 Sep 1, 2022
💥 Beautiful, animated and highly customizable UIPageControl alternative for iOS.

PageControl Requirements iOS 9.0+ Xcode 7.0+ Installation CocoaPods: Add folowing line to Podfile and run 'pod instal'. pod 'Sevruk-PageControl' Or j

Sevruk Development 30 May 2, 2022
Git Submodule Alternative for Cocoa.

CocoaSeeds Git Submodule Alternative for Cocoa. Inspired by CocoaPods. Why? iOS 7 projects do not support the use of Swift libraries from CocoaPods or

Suyeol Jeon 342 Jul 20, 2022