From 26ca47b5117bbea8589b0a5c596b4c830000b67e Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 26 Nov 2018 14:11:13 -0700 Subject: [PATCH] Avoid CaptionTextView animation glitch while dismissing MessageTextView --- .../AttachmentApprovalViewController.swift | 66 +++++++------------ 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift index 5552cb0c7..7f6e61f9a 100644 --- a/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift +++ b/SignalMessaging/ViewControllers/AttachmentApprovalViewController.swift @@ -306,7 +306,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC Logger.debug("\(keyboardStartFrame) -> \(keyboardEndFrame)") lastObservedKeyboardTop = keyboardEndFrame.size.height - currentPageController.updateCaptionViewBottomInset() + let keyboardScenario: KeyboardScenario = bottomToolView.isEditingMediaMessage ? .editingMessage : .editingCaption + currentPageController.updateCaptionViewBottomInset(keyboardScenario: keyboardScenario) } @objc @@ -328,9 +329,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC Logger.debug("\(keyboardStartFrame) -> \(keyboardEndFrame)") - lastObservedKeyboardTop = keyboardEndFrame.size.height + keyboardStartFrame.minY - keyboardEndFrame.minY - - currentPageController.updateCaptionViewBottomInset() + lastObservedKeyboardTop = UIScreen.main.bounds.height - keyboardEndFrame.size.height + currentPageController.updateCaptionViewBottomInset(keyboardScenario: .hidden) } // MARK: - View Helpers @@ -424,7 +424,9 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC // use compact scale when keyboard is popped. let scale: AttachmentPrepViewController.AttachmentViewScale = self.isFirstResponder ? .fullsize : .compact pendingPage.setAttachmentViewScale(scale, animated: false) - pendingPage.updateCaptionViewBottomInset() + + let keyboardScenario: KeyboardScenario = bottomToolView.isEditingMediaMessage ? .editingMessage : .hidden + pendingPage.updateCaptionViewBottomInset(keyboardScenario: keyboardScenario) } } @@ -670,39 +672,13 @@ extension AttachmentApprovalViewController: AttachmentPrepViewControllerDelegate enablePaging() } - var desiredCaptionViewBottomInset: CGFloat { - - let safeAreaInset: CGFloat - if #available(iOS 11, *) { - safeAreaInset = view.safeAreaInsets.bottom - } else { - safeAreaInset = 0 + func desiredCaptionViewBottomInset(keyboardScenario: KeyboardScenario) -> CGFloat { + switch keyboardScenario { + case .hidden, .editingMessage: + return bottomToolView.bounds.height + case .editingCaption: + return lastObservedKeyboardTop } - - // CaptionView bottom offset scenarios: - // - // 1. when no keyboard is popped (e.g. initially) to be *just* above the rail - // 2. when the CaptionView becomes first responder, to be *just* above the keyboard, so the - // user can see what they're typing. - // - // For both these cases we apply the `lastObservedKeyboardTop` - guard bottomToolView.mediaMessageTextToolbar.textView.isFirstResponder else { - // 3. Immediately after dismissing the CaptionView but before the ViewController - // regains firstResponder, there is an instant where the inputAccessoryView is - // not shown, so the lastObservedKeyboardTop is effectively 0. A moment later - // when the ViewController regains firstResponder, the inputAccessoryView will be - // presented. Naively, this would result in the CaptionView undesirably bouncing to - // the bottom of the ViewController, and then immediately back up as the - // inputAccessoryView is presented. - // Instead, we position the CaptionView where it will end up, by using - // `bottomToolView.height`, which will only be greater than - // `lastObserveredKeyboardTop` when the keyboard is not presented. - return max(bottomToolView.bounds.height, lastObservedKeyboardTop) - safeAreaInset - } - - // 4. when the MessageTextView becomes first responder, the keyboard should shift up - // "in front" of the CaptionView - return bottomToolView.bounds.height - safeAreaInset } // MARK: Helpers @@ -759,6 +735,10 @@ extension AttachmentApprovalViewController: GalleryRailViewDelegate { // MARK: - Individual Page +enum KeyboardScenario { + case hidden, editingMessage, editingCaption +} + protocol AttachmentPrepViewControllerDelegate: class { func prepViewController(_ prepViewController: AttachmentPrepViewController, didUpdateCaptionForAttachmentItem attachmentItem: SignalAttachmentItem) @@ -766,7 +746,7 @@ protocol AttachmentPrepViewControllerDelegate: class { func prepViewController(_ prepViewController: AttachmentPrepViewController, didBeginEditingCaptionView captionView: CaptionView) func prepViewController(_ prepViewController: AttachmentPrepViewController, didEndEditingCaptionView captionView: CaptionView) - var desiredCaptionViewBottomInset: CGFloat { get } + func desiredCaptionViewBottomInset(keyboardScenario: KeyboardScenario) -> CGFloat } public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarDelegate, OWSVideoPlayerDelegate { @@ -931,7 +911,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD captionView.delegate = self captionView.autoPinWidthToSuperview() - captionViewBottomConstraint = captionView.autoPinEdge(toSuperviewMargin: .bottom) + captionViewBottomConstraint = captionView.autoPinEdge(toSuperviewEdge: .bottom) } override public func viewWillLayoutSubviews() { @@ -948,14 +928,14 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD var hasLaidOutCaptionView: Bool = false var captionViewBottomConstraint: NSLayoutConstraint! - func updateCaptionViewBottomInset() { + func updateCaptionViewBottomInset(keyboardScenario: KeyboardScenario) { guard let prepDelegate = self.prepDelegate else { owsFailDebug("prepDelegate was unexpectedly nil") return } let changeBlock = { - let offset: CGFloat = -1 * prepDelegate.desiredCaptionViewBottomInset + let offset: CGFloat = -1 * prepDelegate.desiredCaptionViewBottomInset(keyboardScenario: keyboardScenario) self.captionViewBottomConstraint.constant = offset self.captionView.superview?.layoutIfNeeded() } @@ -1229,6 +1209,10 @@ class BottomToolView: UIView { let mediaMessageTextToolbar: MediaMessageTextToolbar let galleryRailView: GalleryRailView + var isEditingMediaMessage: Bool { + return mediaMessageTextToolbar.textView.isFirstResponder + } + let kGalleryRailViewHeight: CGFloat = 72 required init(isAddMoreVisible: Bool) {