move presentation detents settings to modal view controller appearance

This commit is contained in:
Ivan Smolin 2023-07-26 14:37:49 +03:00
parent 8007532351
commit d55745efc6
8 changed files with 76 additions and 71 deletions

View File

@ -28,6 +28,7 @@ extension BaseModalViewController {
open class BaseAppearance: UIView.BaseAppearance<UIView.DefaultWrappedLayout> {
public var presentationDetents: [ModalViewPresentationDetent]
public var dragViewState: DragView.State
public var headerViewState: ModalHeaderView.State
public var footerViewState: ModalFooterView<FooterContentView>.State
@ -36,15 +37,26 @@ extension BaseModalViewController {
backgroundColor: UIColor = .clear,
border: UIViewBorder = .init(),
shadow: UIViewShadow? = nil,
presentationDetents: [ModalViewPresentationDetent] = [.maxHeight],
dragViewState: DragView.State = .hidden,
headerViewState: ModalHeaderView.State = .hidden,
footerViewState: ModalFooterView<FooterContentView>.State = .hidden) {
self.presentationDetents = presentationDetents
self.dragViewState = dragViewState
self.headerViewState = headerViewState
self.footerViewState = footerViewState
super.init(layout: layout, backgroundColor: backgroundColor, border: border, shadow: shadow)
super.init(layout: layout,
backgroundColor: backgroundColor,
border: border,
shadow: shadow)
}
}
public final class DefaultAppearance: BaseAppearance, ViewAppearance {
public static var defaultAppearance: Self {
Self()
}
}
}

View File

@ -153,9 +153,7 @@ open class BaseModalViewController<ContentView: UIView,
// MARK: - Modal View Controller Configuration
open var viewControllerAppearance: BaseAppearance {
.init(backgroundColor: .white)
}
public var viewControllerAppearance: BaseAppearance = .init(backgroundColor: .white)
open var panScrollable: UIScrollView? {
contentView as? UIScrollView
@ -167,9 +165,7 @@ open class BaseModalViewController<ContentView: UIView,
}
}
open var presentationDetents: [ModalViewPresentationDetent] {
[.maxHeight]
}
public var dimmedView: DimmedView? = DimmedView()
open var headerViewHeight: CGFloat {
let dragViewHeight = getHeight(of: dragView)
@ -423,7 +419,7 @@ open class BaseModalViewController<ContentView: UIView,
}
private func getSortedDetents() -> [ModalViewPresentationDetent] {
presentationDetents.uniqued().sorted()
viewControllerAppearance.presentationDetents.uniqued().sorted()
}
private func getHeight(of view: UIView) -> CGFloat {

View File

@ -30,6 +30,9 @@ open class DefaultModalWrapperViewController<ContentController: UIViewController
self.contentViewController = contentViewController
super.init(nibName: nil, bundle: nil)
addChild(contentViewController)
contentViewController.didMove(toParent: self)
}
@available(*, unavailable)
@ -38,6 +41,10 @@ open class DefaultModalWrapperViewController<ContentController: UIViewController
super.init(coder: coder)
}
open override func createContentView() -> UIView {
contentViewController.view
}
}
public extension UIViewController {

View File

@ -24,7 +24,7 @@ import UIKit
import PanModal
open class PassthroughDimmedView: DimmedView {
weak var hitTestHandlerView: UIView?
public weak var hitTestHandlerView: UIView?
public var isTransparent = false

View File

@ -30,21 +30,21 @@ extension UIButton {
appearance.textAttributes?
.configure(button: self,
with: title(for: state),
for: state)
for: state)
if #available(iOS 15, *) {
var config = configuration ?? .plain()
configureInsets(in: &config,
contentInsets: appearance.contentLayout.contentInsets,
titleInsets: appearance.contentLayout.titleInsets,
imageInsets: appearance.contentLayout.imageInsets)
contentInsets: appearance.contentLayout.contentInsets.replacingNan(with: .zero),
titleInsets: appearance.contentLayout.titleInsets.replacingNan(with: .zero),
imageInsets: appearance.contentLayout.imageInsets.replacingNan(with: .zero))
configuration = config
} else {
contentEdgeInsets = appearance.contentLayout.contentInsets
titleEdgeInsets = appearance.contentLayout.titleInsets
imageEdgeInsets = appearance.contentLayout.imageInsets
contentEdgeInsets = appearance.contentLayout.contentInsets.replacingNan(with: .zero)
titleEdgeInsets = appearance.contentLayout.titleInsets.replacingNan(with: .zero)
imageEdgeInsets = appearance.contentLayout.imageInsets.replacingNan(with: .zero)
}
super.configureUIView(appearance: appearance)
@ -67,7 +67,7 @@ extension UIButton {
currentImage
]
.compactMap { $0 }
.first { !($0.size.width.isZero || $0.size.height.isZero) } != nil
.contains { !($0.size.width.isZero || $0.size.height.isZero) }
if hasNonEmptyImage {
let leadingContentInset: CGFloat

View File

@ -27,15 +27,13 @@ open class ContainerSeparatorTableViewCell<View: UIView>: ContainerTableViewCell
private lazy var topSeparatorView = createTopSeparator()
private lazy var bottomSeparatorView = createBottomSeparator()
private var topViewLeftConstraint: NSLayoutConstraint?
private var topViewRightConstraint: NSLayoutConstraint?
private var topViewTopConstraint: NSLayoutConstraint?
private var topViewHeightConstraint: NSLayoutConstraint?
private lazy var topSeparatorConstraints: SubviewConstraints = {
subviewConstraints(for: topSeparatorView)
}()
private var bottomViewLeftConstraint: NSLayoutConstraint?
private var bottomViewRightConstraint: NSLayoutConstraint?
private var bottomViewBottomConstraint: NSLayoutConstraint?
private var bottomViewHeightConstraint: NSLayoutConstraint?
private lazy var bottomSeparatorConstraints: SubviewConstraints = {
subviewConstraints(for: bottomSeparatorView)
}()
open func createTopSeparator() -> UIView {
.init()
@ -93,41 +91,17 @@ open class ContainerSeparatorTableViewCell<View: UIView>: ContainerTableViewCell
open override func configureLayout() {
super.configureLayout()
if let separatorSuperview = topSeparatorView.superview {
topViewTopConstraint = topSeparatorView.topAnchor.constraint(equalTo: separatorSuperview.topAnchor)
topViewRightConstraint = separatorSuperview.rightAnchor.constraint(equalTo: topSeparatorView.rightAnchor)
topViewLeftConstraint = topSeparatorView.leftAnchor.constraint(equalTo: separatorSuperview.leftAnchor)
for view in [topSeparatorView, bottomSeparatorView] {
view.translatesAutoresizingMaskIntoConstraints = false
}
topViewHeightConstraint = topSeparatorView.heightAnchor.constraint(equalToConstant: 1)
if let separatorSuperview = topSeparatorView.superview {
bottomViewRightConstraint = separatorSuperview.rightAnchor.constraint(equalTo: bottomSeparatorView.rightAnchor)
bottomViewLeftConstraint = bottomSeparatorView.leftAnchor.constraint(equalTo: separatorSuperview.leftAnchor)
bottomViewBottomConstraint = bottomSeparatorView.bottomAnchor.constraint(equalTo: separatorSuperview.bottomAnchor)
}
bottomViewHeightConstraint = bottomSeparatorView.heightAnchor.constraint(equalToConstant: 1)
NSLayoutConstraint.activate([
topViewTopConstraint,
topViewRightConstraint,
topViewLeftConstraint,
topViewHeightConstraint,
bottomViewRightConstraint,
bottomViewLeftConstraint,
bottomViewBottomConstraint,
bottomViewHeightConstraint
].compactMap { $0 })
}
open override func configureAppearance() {
super.configureAppearance()
[topSeparatorView, bottomSeparatorView].forEach {
$0.isHidden = true
$0.backgroundColor = .black
$0.translatesAutoresizingMaskIntoConstraints = false
for view in [topSeparatorView, bottomSeparatorView] {
view.isHidden = true
view.backgroundColor = .black
}
}
@ -136,20 +110,37 @@ open class ContainerSeparatorTableViewCell<View: UIView>: ContainerTableViewCell
private func updateTopSeparator(with appearance: SeparatorAppearance) {
topSeparatorView.configureUIView(appearance: appearance)
topViewHeightConstraint?.constant = appearance.layout.size.height
topViewTopConstraint?.constant = appearance.layout.insets.top
topViewLeftConstraint?.constant = appearance.layout.insets.left
topViewRightConstraint?.constant = appearance.layout.insets.right
topSeparatorConstraints.update(from: appearance.layout)
}
private func updateBottomSeparator(with appearance: SeparatorAppearance) {
bottomSeparatorView.configureUIView(appearance: appearance)
bottomViewHeightConstraint?.constant = appearance.layout.size.height
bottomSeparatorConstraints.update(from: appearance.layout)
}
bottomViewBottomConstraint?.constant = appearance.layout.insets.bottom
bottomViewLeftConstraint?.constant = appearance.layout.insets.left
bottomViewRightConstraint?.constant = appearance.layout.insets.right
private func subviewConstraints(for seperatorView: UIView) -> SubviewConstraints {
let leadingConstraint = seperatorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
let trailingConstraint = seperatorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
let topConstraint = seperatorView.topAnchor.constraint(equalTo: contentView.topAnchor)
let bottomConstraint = seperatorView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
let edgeConstraints = EdgeConstraints(leadingConstraint: leadingConstraint,
trailingConstraint: trailingConstraint,
topConstraint: topConstraint,
bottomConstraint: bottomConstraint)
let centerXConstraint = seperatorView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor)
let centerYConstraint = seperatorView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)
let centerConstraints = CenterConstraints(centerXConstraint: centerXConstraint,
centerYConstraint: centerYConstraint)
let sizeConstraints = SizeConstraints(widthConstraint: seperatorView.widthAnchor.constraint(equalToConstant: .zero),
heightConstraint: seperatorView.heightAnchor.constraint(equalToConstant: .zero))
return SubviewConstraints(edgeConstraints: edgeConstraints,
centerConstraints: centerConstraints,
sizeConstraints: sizeConstraints)
}
}

View File

@ -47,14 +47,6 @@ public struct SubviewConstraints: ConstraintsSet {
centerConstraints.update(offset: centerOffset)
sizeConstraints.update(from: size)
edgeConstraints.update(from: insets)
for verticalConstraint in edgeConstraints.vertical {
verticalConstraint.isActive = !centerOffset.vertical.isFinite
}
for horizontalConstraint in edgeConstraints.horizontal {
horizontalConstraint.isActive = !centerOffset.horizontal.isFinite
}
}
// MARK: - WrappedViewLayout shortcut

View File

@ -72,6 +72,13 @@ public extension UIEdgeInsets {
.init(top: top, left: left, bottom: bottom, right: right)
}
func replacingNan(with defaultValue: CGFloat) -> Self {
.init(top: top.isFinite ? top : defaultValue,
left: left.isFinite ? left : defaultValue,
bottom: bottom.isFinite ? bottom : defaultValue,
right: right.isFinite ? right : defaultValue)
}
func add(_ lhsKeyPath: KeyPath<Self, CGFloat>,
to rhsKeyPath: KeyPath<Self, CGFloat>,
of rhs: Self,