Who can help me? I create chat controller via UITableViewController, UINavigationController and I use InputAccessoryView. If I swipe screen to left (dismiss this controller) and return swipe to right (cancel dismiss) - table set adjustContentInset bottom to zero and InputAcessoryView close bottom content tableView. This problem created in ViewWillAppear event. My code:
UITableViewController:
// MARK: - Controller data
lazy var inputContainerView = ChatAccessoryView(frame: .zero, buttonSelector: #selector(sendMessage(sender:)), controller: self)
public var ticketID: Int = 0
private var lastMessageID: Int = 0
private var tableSections: [String] = []
private var tableRows: [[SupportTicketMessage]] = []
private var sendingMessage: Bool = false
private var URLTaskGetMessages: URLSessionDataTask?
private var URLTaskSendMessage: URLSessionDataTask?
// MARK: - Controller overrides
override func loadView() {
super.loadView()
tableView.register(ChatHeaderView.self, forHeaderFooterViewReuseIdentifier: "chatHeader")
tableView.register(ChatFromMessageTableViewCell.self, forCellReuseIdentifier: "chatFromMessage")
tableView.register(ChatToMessageTableViewCell.self, forCellReuseIdentifier: "chatToMessage")
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
if let messages = supportClass.getTicketMessages(ticketID) {
tableSections = messages.sections
tableRows = messages.rows
lastMessageID = messages.lastMessage
scrollTableToBottom(false)
} else {
tableView.setLoaderBackground("Загрузка сообщений...")
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
loadMessages()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
URLTaskGetMessages?.cancel()
URLTaskSendMessage?.cancel()
}
override var inputAccessoryView: UIView? {
return inputContainerView
}
override var canBecomeFirstResponder: Bool {
return true
}
ChatAccessoryView:
class ChatAccessoryView: UIView {
// MARK: - Get params to init
let buttonSelector: Selector
let controller: UIViewController
// MARK: - Data
private let textView = ChatTextView()
private let sendButton = LoadingButton(frame: .zero, text: "Отпр.")
private let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .extraLight))
// MARK: - Init
required init(frame: CGRect, buttonSelector: Selector, controller: UIViewController) {
self.buttonSelector = buttonSelector
self.controller = controller
super.init(frame: frame)
configureContents()
blurEffectConfigure()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Overrides
override var intrinsicContentSize: CGSize {
return .zero
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
blurEffectConfigure()
}
override func didMoveToWindow() {
super.didMoveToWindow()
if let window = window {
textView.bottomAnchor.constraint(lessThanOrEqualToSystemSpacingBelow: window.safeAreaLayoutGuide.bottomAnchor, multiplier: 1.0).isActive = true
}
}
// MARK: - Private methods
private func configureContents() {
backgroundColor = .clear
autoresizingMask = .flexibleHeight
textView.placeholder = "Напишите сообщение..."
textView.maxHeight = 160
textView.font = .systemFont(ofSize: 17)
textView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
textView.layer.cornerRadius = 8
textView.textContainerInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 4)
sendButton.titleLabel?.font = .boldSystemFont(ofSize: 17)
sendButton.setTitleColor(controller.view.tintColor, for: .normal)
sendButton.addTarget(controller, action: buttonSelector, for: .touchUpInside)
blurView.translatesAutoresizingMaskIntoConstraints = false
textView.translatesAutoresizingMaskIntoConstraints = false
sendButton.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(blurView)
self.addSubview(textView)
self.addSubview(sendButton)
blurView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
blurView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
blurView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
blurView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
textView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20).isActive = true
textView.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
textView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8 ).isActive = true
textView.trailingAnchor.constraint(equalTo: sendButton.leadingAnchor, constant: -20).isActive = true
sendButton.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20).isActive = true
sendButton.widthAnchor.constraint(equalToConstant: 48).isActive = true
sendButton.centerYAnchor.constraint(equalTo: textView.centerYAnchor).isActive = true
}
private func blurEffectConfigure() {
if #available(iOS 13.0, *) {
if traitCollection.userInterfaceStyle == .light {
blurView.effect = UIBlurEffect(style: .extraLight)
} else {
blurView.effect = UIBlurEffect(style: .dark)
}
}
}
// MARK: - Public methods
public func successSend() {
textView.text = ""
sendButton.loadingMode(false)
}
}
ChatTextView:
class ChatTextView: UITextView {
// MARK: - Data
var maxHeight: CGFloat = 0.0
public let placeholderTextView: UITextView = {
let textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.backgroundColor = .clear
textView.isScrollEnabled = false
textView.isUserInteractionEnabled = false
textView.textColor = UIColor.black.withAlphaComponent(0.33)
return textView
}()
var placeholder: String? {
get {
return placeholderTextView.text
}
set {
placeholderTextView.text = newValue
}
}
// MARK: - Init
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
backgroundColor = UIColor.black.withAlphaComponent(0.06)
isScrollEnabled = false
autoresizingMask = [.flexibleWidth, .flexibleHeight]
NotificationCenter.default.addObserver(self, selector: #selector(UITextInputDelegate.textDidChange(_:)), name: UITextView.textDidChangeNotification, object: self)
placeholderTextView.font = font
addSubview(placeholderTextView)
NSLayoutConstraint.activate([
placeholderTextView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
placeholderTextView.trailingAnchor.constraint(equalTo: trailingAnchor),
placeholderTextView.topAnchor.constraint(equalTo: topAnchor),
placeholderTextView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
colorThemeConfigure()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Overrides
override var text: String! {
didSet {
invalidateIntrinsicContentSize()
placeholderTextView.isHidden = !text.isEmpty
}
}
override var font: UIFont? {
didSet {
placeholderTextView.font = font
invalidateIntrinsicContentSize()
}
}
override var contentInset: UIEdgeInsets {
didSet {
placeholderTextView.contentInset = contentInset
}
}
override var intrinsicContentSize: CGSize {
var size = super.intrinsicContentSize
if size.height == UIView.noIntrinsicMetric {
layoutManager.glyphRange(for: textContainer)
size.height = layoutManager.usedRect(for: textContainer).height + textContainerInset.top + textContainerInset.bottom
}
if maxHeight > 0.0 && size.height > maxHeight {
size.height = maxHeight
if !isScrollEnabled {
isScrollEnabled = true
}
} else if isScrollEnabled {
isScrollEnabled = false
}
return size
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
colorThemeConfigure()
}
// MARK: - Private methods
private func colorThemeConfigure() {
if #available(iOS 13.0, *) {
if traitCollection.userInterfaceStyle == .light {
backgroundColor = UIColor.black.withAlphaComponent(0.06)
placeholderTextView.textColor = UIColor.black.withAlphaComponent(0.33)
} else {
backgroundColor = UIColor.white.withAlphaComponent(0.08)
placeholderTextView.textColor = UIColor.white.withAlphaComponent(0.33)
}
}
}
// MARK: - Obj C methods
@objc private func textDidChange(_ note: Notification) {
invalidateIntrinsicContentSize()
placeholderTextView.isHidden = !text.isEmpty
}
}
Screenshots error:
Swipe screen to left and cancel this action (swipe right)
When I returned to controller I see this Bug (last message go to bottom)
Thanks!
Thank you all for your attention and trying to help me! I solved the problem as follows:
tableView.contentInsetAdjustmentBehavior = .never
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 53, right: 0)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
I disable automatic tableView.contentInsetAdjustmentBehavior and use tableView.conentInset. On open/close keyboard I change tableView.contentInset.