GithubHelp home page GithubHelp logo

Comments (5)

ekazaev avatar ekazaev commented on May 22, 2024 1

@Sabellus Hi, thank you for your question.

First of all. If I correctly understood your description of inputAccessoryView behaviour. Apple broke the inputAccessoryView behaviour in IOS 16. So you can not use it anymore. If you compile your app with IOS 15 SDK it behves fine. I reported a bug and I know other people reported it, but it seems that Apple developers are not going to fix it anytime soon. You can find same jumpy behaviour in Facebook messenger for instance. So I would recommend to bring your input view to the actual view controller and attach it to keyboardLayoutGuide. You need a few hacks there but overall it works fine. Dont forget to change the keyboard inset setting code on keyboard presentation to:

    func keyboardWillChangeFrame(info: KeyboardInfo) {
        // ....
        let keyboardOffset = max(0, view.safeAreaLayoutGuide.layoutFrame.maxY - view.keyboardLayoutGuide.layoutFrame.minY)
        // ....
     }

In regard to message population as far as I remember push animation creates an extra animation loop so automatic inset value changes also happen with animation. As far as i remember thats why you need to populate collection and set thouse insets yourself at first time outside of that animation curve. So you want to do in your view controller something like:

    private var isFirsAppearance = true

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // Hack to prevent animation of the contentInset of first appearance. The same is used in MessageKit
        if isFirsAppearance {
            isFirsAppearance = false
            setupInsets()
            let initialCells = eventHandler.getInitialCells()
            if !initialCells.isEmpty {
                processUpdates(with: initialCells, animated: false, ignoreInterfaceActions: true)
            }
        }
    }

from chatlayout.

ekazaev avatar ekazaev commented on May 22, 2024 1

@Sabellus Yep you understand in general fine. But you should understand I am giving you a theoretical code. I can not write it for you. I can only give you some directions.

Keyboard appearance function will look someting like:

    func keyboardWillChangeFrame(info: KeyboardInfo) {
        guard !currentInterfaceActions.options.contains(.changingFrameSize),
              !currentInterfaceActions.options.contains(.showingPreview),
              !currentInterfaceActions.options.contains(.viewIsDisappearing),
              collectionView.contentInsetAdjustmentBehavior != .never else {
            return
        }

        currentInterfaceActions.options.insert(.changingKeyboardFrame)
        let keyboardAccessoryHeight = self.keyboardAccessoryView.bounds.height
        let keyboardOffset = max(0, view.safeAreaLayoutGuide.layoutFrame.maxY - view.keyboardLayoutGuide.layoutFrame.minY)
        let newBottomInset = keyboardOffset + keyboardAccessoryHeight

        if collectionView.contentInset.bottom != newBottomInset {
            let positionSnapshot = chatLayout.getContentOffsetSnapshot(from: .bottom)

            // Blocks possible updates when keyboard is being hidden interactively
            currentInterfaceActions.options.insert(.changingContentInsets)
            UIView.animate(withDuration: info.animationDuration, animations: { [weak self] in
                guard let self = self else { return }

                self.collectionView.performBatchUpdates({ [weak self] in
                    guard let self = self else { return }
                    self.collectionView.contentInset.bottom = newBottomInset
                    self.collectionView.verticalScrollIndicatorInsets.bottom = newBottomInset
                }, completion: nil)

                if let positionSnapshot = positionSnapshot, !self.isUserInitiatedScrolling {
                    self.chatLayout.restoreContentOffset(with: positionSnapshot)
                }
            }, completion: { [weak self] _ in
                self?.currentInterfaceActions.options.remove(.changingContentInsets)
            })
        }
    }

evenHandler in this case something that will return initial cells in the collection view
setupInsets looks something like

func setupInsets() {
        let insets = UIEdgeInsets(
            top: 0,
            left: 0,
            bottom: inputBarView.bounds.height - view.safeAreaInsets.bottom,
            right: 0
        )
        collectionView.contentInset = insets
        collectionView.scrollIndicatorInsets = insets
    }

I can not guarantee that is the only place you need changes. But I know that it is possible what you want to achieve.

from chatlayout.

Sabellus avatar Sabellus commented on May 22, 2024 1

Appreciate your help! It works ❤

from chatlayout.

Sabellus avatar Sabellus commented on May 22, 2024

What exactly should I do?

  1. remove
    override var inputAccessoryView: UIView? {
        inputBarView
    }

    override var canBecomeFirstResponder: Bool {
        true
    }
  1. adding and change
    view.addSubview(inputBarView)
    inputBarView.bottomAnchor.constraint(equalTo: self.view.keyboardLayoutGuide.topAnchor).isActive = true
    collectionView.bottomAnchor.constraint(equalTo: inputBarView.topAnchor, constant: 0),
  1. where to add this: let keyboardOffset = max(0, view.safeAreaLayoutGuide.layoutFrame.maxY - view.keyboardLayoutGuide.layoutFrame.minY)
func keyboardWillChangeFrame(info: KeyboardInfo) {
        guard !currentInterfaceActions.options.contains(.changingFrameSize),
              collectionView.contentInsetAdjustmentBehavior != .never,
              let keyboardFrame = collectionView.window?.convert(info.frameEnd, to: view),
              keyboardFrame.minY > 0,
              collectionView.convert(collectionView.bounds, to: collectionView.window).maxY > info.frameEnd.minY else {
            return
        }
        currentInterfaceActions.options.insert(.changingKeyboardFrame)
        let newBottomInset = collectionView.frame.minY + collectionView.frame.size.height - keyboardFrame.minY - collectionView.safeAreaInsets.bottom
        if newBottomInset > 0,
           collectionView.contentInset.bottom != newBottomInset {
            let positionSnapshot = chatLayout.getContentOffsetSnapshot(from: .bottom)

  1. setupInsets() what is there?
    eventHandler what is there?
     private var isFirsAppearance = true
     override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // Hack to prevent animation of the contentInset of first appearance. The same is used in MessageKit
        if isFirsAppearance {
            isFirsAppearance = false
            setupInsets()
            let initialCells = eventHandler.getInitialCells()
            if !initialCells.isEmpty {
                processUpdates(with: initialCells, animated: false, ignoreInterfaceActions: true)
            }
        }
     }

from chatlayout.

ekazaev avatar ekazaev commented on May 22, 2024

You are very welcome @Sabellus. Best of luck

from chatlayout.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.