fix: keyboard overlapping for footer and content view of BaseModalViewController
This commit is contained in:
parent
0ef1edfacb
commit
8007532351
|
|
@ -151,9 +151,6 @@ open class BaseModalViewController<ContentView: UIView,
|
|||
sizeConstraints: sizeConstraints)
|
||||
}()
|
||||
|
||||
public var keyboardDidShownObserver: NSObjectProtocol?
|
||||
public var keyboardDidHiddenObserver: NSObjectProtocol?
|
||||
|
||||
// MARK: - Modal View Controller Configuration
|
||||
|
||||
open var viewControllerAppearance: BaseAppearance {
|
||||
|
|
@ -164,6 +161,12 @@ open class BaseModalViewController<ContentView: UIView,
|
|||
contentView as? UIScrollView
|
||||
}
|
||||
|
||||
public var panScrollableInsets: UIEdgeInsets = .zero {
|
||||
didSet {
|
||||
panScrollable?.contentInset = panScrollableInsets
|
||||
}
|
||||
}
|
||||
|
||||
open var presentationDetents: [ModalViewPresentationDetent] {
|
||||
[.maxHeight]
|
||||
}
|
||||
|
|
@ -199,24 +202,23 @@ open class BaseModalViewController<ContentView: UIView,
|
|||
return detents.min()?.panModalHeight(headerHeight: headerViewHeight) ?? .maxHeight
|
||||
}
|
||||
|
||||
private var keyboardDidShownObserver: NSObjectProtocol?
|
||||
private var keyboardDidHiddenObserver: NSObjectProtocol?
|
||||
|
||||
// MARK: - Life Cycle
|
||||
|
||||
deinit {
|
||||
let notificationCenter = NotificationCenter.default
|
||||
|
||||
if let keyboardDidShownObserver {
|
||||
NotificationCenter.default.removeObserver(keyboardDidShownObserver)
|
||||
notificationCenter.removeObserver(keyboardDidShownObserver)
|
||||
}
|
||||
|
||||
if let keyboardDidHiddenObserver {
|
||||
NotificationCenter.default.removeObserver(keyboardDidHiddenObserver)
|
||||
notificationCenter.removeObserver(keyboardDidHiddenObserver)
|
||||
}
|
||||
}
|
||||
|
||||
open override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
adjustScrollViewIfNeeded()
|
||||
}
|
||||
|
||||
// MARK: - BaseInitializableViewController
|
||||
|
||||
open override func addViews() {
|
||||
|
|
@ -280,33 +282,25 @@ open class BaseModalViewController<ContentView: UIView,
|
|||
return
|
||||
}
|
||||
|
||||
if let panScrollable {
|
||||
if isKeyboardHidden {
|
||||
adjustScrollViewIfNeeded()
|
||||
} else {
|
||||
panScrollable.contentInset = .vertical(bottom: keyboardHeight)
|
||||
}
|
||||
} else if case let .presented(footerViewAppearance) = viewControllerAppearance.footerViewState {
|
||||
if case let .presented(footerViewAppearance) = viewControllerAppearance.footerViewState {
|
||||
let bottomInset = footerViewAppearance.layout.insets.add(\.bottom,
|
||||
to: \.bottom,
|
||||
of: .vertical(bottom: keyboardHeight))
|
||||
|
||||
footerViewConstraints.edgeConstraints.bottomConstraint.constant = bottomInset
|
||||
} else if let panScrollable {
|
||||
var insets = panScrollableInsets
|
||||
|
||||
if isKeyboardHidden {
|
||||
panScrollable.contentInset = insets
|
||||
} else {
|
||||
insets.bottom += keyboardHeight
|
||||
|
||||
panScrollable.contentInset = insets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open func adjustScrollViewIfNeeded() {
|
||||
guard let panScrollable, case let .presented(footerViewAppearance) = viewControllerAppearance.footerViewState else {
|
||||
return
|
||||
}
|
||||
|
||||
let verticalInsets = footerViewAppearance.layout.insets.vertical(onNan: .zero)
|
||||
let subviewVerticalInsets = footerViewAppearance.subviewAppearance.layout.insets.vertical(onNan: .zero)
|
||||
let totalHeight = getHeight(of: footerView) + verticalInsets + subviewVerticalInsets
|
||||
|
||||
panScrollable.contentInset = .vertical(bottom: totalHeight)
|
||||
}
|
||||
|
||||
// MARK: - Private Methods
|
||||
|
||||
private func configureDragViewLayout() {
|
||||
|
|
|
|||
|
|
@ -22,20 +22,26 @@
|
|||
|
||||
import UIKit
|
||||
|
||||
open class BaseModalWrapperViewController<ContentViewController>: BaseModalViewController<UIView, UIView>
|
||||
where ContentViewController: UIViewController {
|
||||
open class DefaultModalWrapperViewController<ContentController: UIViewController>: BaseModalViewController<UIView, UIView> {
|
||||
|
||||
private(set) public lazy var contentViewController = createContentViewController()
|
||||
private(set) public var contentViewController: ContentController
|
||||
|
||||
// MARK: - BaseModalViewController
|
||||
public init(contentViewController: ContentController) {
|
||||
self.contentViewController = contentViewController
|
||||
|
||||
open override func createContentView() -> UIView {
|
||||
contentViewController.view
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
@available(*, unavailable)
|
||||
required public init?(coder: NSCoder) {
|
||||
contentViewController = ContentController()
|
||||
|
||||
open func createContentViewController() -> ContentViewController {
|
||||
ContentViewController()
|
||||
super.init(coder: coder)
|
||||
}
|
||||
}
|
||||
|
||||
public extension UIViewController {
|
||||
func wrappedInBottomSheetController() -> DefaultModalWrapperViewController<UIViewController> {
|
||||
DefaultModalWrapperViewController(contentViewController: self)
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ public final class DragView: BaseInitializableView, AppearanceConfigurable {
|
|||
public final class Appearance: UIView.BaseWrappedAppearance<UIView.DefaultWrappedLayout>, WrappedViewAppearance {
|
||||
|
||||
public static var defaultAppearance: Appearance {
|
||||
Self().update { dragView in
|
||||
.make { dragView in
|
||||
dragView.backgroundColor = Constants.dragViewBackgroundColor
|
||||
dragView.border = Constants.dragViewBorder
|
||||
|
||||
|
|
|
|||
|
|
@ -24,13 +24,10 @@ import TIUIElements
|
|||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
public typealias ModalFooterView<ContentView: UIView> = ContainerView<ContentView>
|
||||
|
||||
public extension ModalFooterView {
|
||||
|
||||
open class ModalFooterView<ContentView: UIView>: ContainerView<ContentView> {
|
||||
// MARK: - Nested Types
|
||||
|
||||
enum State {
|
||||
public enum State {
|
||||
case hidden
|
||||
case presented(BaseWrappedViewHolderAppearance<DefaultWrappedAppearance, DefaultWrappedLayout>)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,31 +42,31 @@ open class ModalHeaderView: BaseInitializableView, AppearanceConfigurable {
|
|||
|
||||
// MARK: - Public properties
|
||||
|
||||
public let leftButton = StatefulButton()
|
||||
public let rightButton = StatefulButton()
|
||||
public let leadingButton = StatefulButton()
|
||||
public let trailingButton = StatefulButton()
|
||||
|
||||
public private(set) lazy var leftTrailingToRightLeadingConstraint: NSLayoutConstraint = {
|
||||
leftButton.trailingAnchor.constraint(equalTo: rightButton.leadingAnchor)
|
||||
leadingButton.trailingAnchor.constraint(equalTo: trailingButton.leadingAnchor)
|
||||
}()
|
||||
|
||||
public private(set) lazy var leftTrailingToSuperviewTrailing: NSLayoutConstraint = {
|
||||
leftButton.trailingAnchor.constraint(equalTo: rightButton.leadingAnchor)
|
||||
leadingButton.trailingAnchor.constraint(equalTo: trailingButton.leadingAnchor)
|
||||
}()
|
||||
|
||||
public private(set) lazy var leftButtonConstraints: SubviewConstraints = {
|
||||
let edgeConstraints = EdgeConstraints(leadingConstraint: leftButton.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
let edgeConstraints = EdgeConstraints(leadingConstraint: leadingButton.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
trailingConstraint: leftTrailingToRightLeadingConstraint,
|
||||
topConstraint: leftButton.topAnchor.constraint(equalTo: topAnchor),
|
||||
bottomConstraint: leftButton.bottomAnchor.constraint(equalTo: bottomAnchor))
|
||||
topConstraint: leadingButton.topAnchor.constraint(equalTo: topAnchor),
|
||||
bottomConstraint: leadingButton.bottomAnchor.constraint(equalTo: bottomAnchor))
|
||||
|
||||
let centerXConstraint = leftButton.centerXAnchor.constraint(equalTo: centerXAnchor)
|
||||
let centerYConstraint = leftButton.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
let centerXConstraint = leadingButton.centerXAnchor.constraint(equalTo: centerXAnchor)
|
||||
let centerYConstraint = leadingButton.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
|
||||
let centerConstraints = CenterConstraints(centerXConstraint: centerXConstraint,
|
||||
centerYConstraint: centerYConstraint)
|
||||
|
||||
let sizeConstraints = SizeConstraints(widthConstraint: leftButton.widthAnchor.constraint(equalToConstant: .zero),
|
||||
heightConstraint: leftButton.heightAnchor.constraint(equalToConstant: .zero))
|
||||
let sizeConstraints = SizeConstraints(widthConstraint: leadingButton.widthAnchor.constraint(equalToConstant: .zero),
|
||||
heightConstraint: leadingButton.heightAnchor.constraint(equalToConstant: .zero))
|
||||
|
||||
return SubviewConstraints(edgeConstraints: edgeConstraints,
|
||||
centerConstraints: centerConstraints,
|
||||
|
|
@ -74,25 +74,26 @@ open class ModalHeaderView: BaseInitializableView, AppearanceConfigurable {
|
|||
}()
|
||||
|
||||
public private(set) lazy var rightLeadingToSuperviewLeadingConstraint: NSLayoutConstraint = {
|
||||
rightButton.leadingAnchor.constraint(equalTo: leadingAnchor)
|
||||
trailingButton.leadingAnchor.constraint(equalTo: leadingAnchor)
|
||||
}()
|
||||
|
||||
public private(set) lazy var rightButtonConstraints: SubviewConstraints = {
|
||||
let trailingConstraint = rightButton.trailingAnchor.constraint(equalTo: trailingAnchor)
|
||||
let leadingConstraint = trailingButton.leadingAnchor.constraint(equalTo: leadingAnchor)
|
||||
let trailingConstraint = trailingButton.trailingAnchor.constraint(equalTo: trailingAnchor)
|
||||
|
||||
let edgeConstraints = EdgeConstraints(leadingConstraint: rightButton.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
let edgeConstraints = EdgeConstraints(leadingConstraint: leadingConstraint,
|
||||
trailingConstraint: trailingConstraint,
|
||||
topConstraint: rightButton.topAnchor.constraint(equalTo: topAnchor),
|
||||
bottomConstraint: rightButton.bottomAnchor.constraint(equalTo: bottomAnchor))
|
||||
topConstraint: trailingButton.topAnchor.constraint(equalTo: topAnchor),
|
||||
bottomConstraint: trailingButton.bottomAnchor.constraint(equalTo: bottomAnchor))
|
||||
|
||||
let centerXConstraint = rightButton.centerXAnchor.constraint(equalTo: centerXAnchor)
|
||||
let centerYConstraint = rightButton.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
let centerXConstraint = trailingButton.centerXAnchor.constraint(equalTo: centerXAnchor)
|
||||
let centerYConstraint = trailingButton.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
|
||||
let centerConstraints = CenterConstraints(centerXConstraint: centerXConstraint,
|
||||
centerYConstraint: centerYConstraint)
|
||||
|
||||
let sizeConstraints = SizeConstraints(widthConstraint: rightButton.widthAnchor.constraint(equalToConstant: .zero),
|
||||
heightConstraint: rightButton.heightAnchor.constraint(equalToConstant: .zero))
|
||||
let sizeConstraints = SizeConstraints(widthConstraint: trailingButton.widthAnchor.constraint(equalToConstant: .zero),
|
||||
heightConstraint: trailingButton.heightAnchor.constraint(equalToConstant: .zero))
|
||||
|
||||
return SubviewConstraints(edgeConstraints: edgeConstraints,
|
||||
centerConstraints: centerConstraints,
|
||||
|
|
@ -106,14 +107,15 @@ open class ModalHeaderView: BaseInitializableView, AppearanceConfigurable {
|
|||
open override func addViews() {
|
||||
super.addViews()
|
||||
|
||||
addSubviews(leftButton, rightButton)
|
||||
addSubviews(leadingButton, trailingButton)
|
||||
}
|
||||
|
||||
open override func configureLayout() {
|
||||
super.configureLayout()
|
||||
|
||||
[leftButton, rightButton]
|
||||
.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
|
||||
for view in [leadingButton, trailingButton] {
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - AppearanceConfigurable
|
||||
|
|
@ -154,8 +156,8 @@ open class ModalHeaderView: BaseInitializableView, AppearanceConfigurable {
|
|||
view.configureUIView(appearance: appearance)
|
||||
}
|
||||
|
||||
configure(buttonStyle: leadingButtonStyle, forButton: leftButton, constraints: leftButtonConstraints)
|
||||
configure(buttonStyle: trailingButtonStyle, forButton: rightButton, constraints: rightButtonConstraints)
|
||||
configure(buttonStyle: leadingButtonStyle, forButton: leadingButton, constraints: leftButtonConstraints)
|
||||
configure(buttonStyle: trailingButtonStyle, forButton: trailingButton, constraints: rightButtonConstraints)
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ open class BasePlaceholderView<ImageView: UIView>: BaseInitializableView {
|
|||
sizeConstraints: sizeConstraints)
|
||||
}()
|
||||
|
||||
public var keyboardDidShownObserver: NSObjectProtocol?
|
||||
public var keyboardDidHiddenObserver: NSObjectProtocol?
|
||||
private var keyboardDidShownObserver: NSObjectProtocol?
|
||||
private var keyboardDidHiddenObserver: NSObjectProtocol?
|
||||
|
||||
open var isImageViewHidden: Bool {
|
||||
imageView.isHidden
|
||||
|
|
@ -112,6 +112,18 @@ open class BasePlaceholderView<ImageView: UIView>: BaseInitializableView {
|
|||
controlsStackView.isHidden || controlsStackView.arrangedSubviews.isEmpty
|
||||
}
|
||||
|
||||
deinit {
|
||||
let notificationCenter = NotificationCenter.default
|
||||
|
||||
if let keyboardDidShownObserver {
|
||||
notificationCenter.removeObserver(keyboardDidShownObserver)
|
||||
}
|
||||
|
||||
if let keyboardDidHiddenObserver {
|
||||
notificationCenter.removeObserver(keyboardDidHiddenObserver)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - BaseInitializableView
|
||||
|
||||
open override func addViews() {
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@ open class CollectionTableViewCell<CollectionView: UICollectionView>: ContainerT
|
|||
}
|
||||
|
||||
let cachedCollectionFrame = wrappedView.frame
|
||||
wrappedView.frame.size.width = targetSize.width - wrappedContentInsets.left - wrappedContentInsets.right
|
||||
wrappedView.frame.size.width = targetSize.width - wrappedContentInsets.horizontal(onNan: .zero)
|
||||
let collectionContentHeight = wrappedView.collectionViewLayout.collectionViewContentSize.height
|
||||
wrappedView.frame = cachedCollectionFrame
|
||||
|
||||
return CGSize(width: targetSize.width,
|
||||
height: collectionContentHeight + wrappedContentInsets.top + wrappedContentInsets.bottom)
|
||||
height: collectionContentHeight + wrappedContentInsets.vertical(onNan: .zero))
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
public final class ContainerView<View: UIView>: BaseInitializableView, WrappedViewHolder {
|
||||
open class ContainerView<View: UIView>: BaseInitializableView, WrappedViewHolder {
|
||||
|
||||
public private(set) lazy var wrappedView = View()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue