Skip to content

Commit

Permalink
Make the FloatingPanelAdaptiveLayoutAnchor impl obvious
Browse files Browse the repository at this point in the history
* Removed incorrect constraints
* Renamed FloatingPanelLayout{ => Content}BoundingGuide
* Updated the doc comments
  • Loading branch information
scenee committed Jan 9, 2023
1 parent bdc1755 commit 04aa5b5
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ final class AdaptiveLayoutTestViewController: UIViewController, UITableViewDeleg
absoluteOffset: 0.0,
contentLayout: targetGuide,
referenceGuide: .superview,
boundingGuide: .superview
contentBoundingGuide: .safeArea
),
.half: FloatingPanelAdaptiveLayoutAnchor(
fractionalOffset: 0.5,
contentLayout: targetGuide,
referenceGuide: .superview,
boundingGuide: .safeArea
contentBoundingGuide: .safeArea
),
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,25 @@ import FloatingPanel

final class ImageViewController: UIViewController {
class PanelLayout: FloatingPanelLayout {
weak var targetGuide: UILayoutGuide?
init(targetGuide: UILayoutGuide?) {
private unowned var targetGuide: UILayoutGuide
init(targetGuide: UILayoutGuide) {
self.targetGuide = targetGuide
}
let position: FloatingPanelPosition = .bottom
let initialState: FloatingPanelState = .full
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
if #available(iOS 11.0, *), let targetGuide = targetGuide {
return [
.full: FloatingPanelAdaptiveLayoutAnchor(absoluteOffset: 0,
contentLayout: targetGuide,
referenceGuide: .superview),
.half: FloatingPanelAdaptiveLayoutAnchor(fractionalOffset: 0.5,
contentLayout: targetGuide,
referenceGuide: .superview)
]
} else {
return [
.full: FloatingPanelLayoutAnchor(absoluteInset: 500,
edge: .bottom,
referenceGuide: .superview)
]
}
return [
.full: FloatingPanelAdaptiveLayoutAnchor(
absoluteOffset: 0,
contentLayout: targetGuide,
referenceGuide: .superview
),
.half: FloatingPanelAdaptiveLayoutAnchor(
fractionalOffset: 0.5,
contentLayout: targetGuide,
referenceGuide: .superview
)
]
}
}

Expand Down
10 changes: 3 additions & 7 deletions Examples/Samples/Sources/UseCases/UseCaseController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,9 @@ extension UseCaseController {
fpc.set(contentViewController: contentVC)
fpc.ext_trackScrollView(in: contentVC)
if case let contentVC as ImageViewController = contentVC {
if #available(iOS 11.0, *) {
let mode: ImageViewController.Mode = (useCase == .showAdaptivePanelWithCustomGuide) ? .withHeaderFooter : .onlyImage
let layoutGuide = contentVC.layoutGuideFor(mode: mode)
fpc.layout = ImageViewController.PanelLayout(targetGuide: layoutGuide)
} else {
fpc.layout = ImageViewController.PanelLayout(targetGuide: nil)
}
let mode: ImageViewController.Mode = (useCase == .showAdaptivePanelWithCustomGuide) ? .withHeaderFooter : .onlyImage
let layoutGuide = contentVC.layoutGuideFor(mode: mode)
fpc.layout = ImageViewController.PanelLayout(targetGuide: layoutGuide)
}
addMain(panel: fpc)

Expand Down
1 change: 1 addition & 0 deletions Sources/FloatingPanel.docc/FloatingPanel.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The new interface displays the related contents and utilities in parallel as a u
- ``FloatingPanelPosition``
- ``FloatingPanelReferenceEdge``
- ``FloatingPanelLayoutReferenceGuide``
- ``FloatingPanelLayoutContentBoundingGuide``

### Behaviors

Expand Down
20 changes: 11 additions & 9 deletions Sources/Layout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ class LayoutAdapter {
private(set) var attractionConstraint: NSLayoutConstraint?

private var staticConstraint: NSLayoutConstraint?
private var boundingConstraint: NSLayoutConstraint?

/// A layout constraint to limit the content size on ``FloatingPanelAdaptiveLayoutAnchor``.
private var contentBoundingConstraint: NSLayoutConstraint?

private var anchorStates: Set<FloatingPanelState> {
return Set(layout.anchors.keys)
Expand Down Expand Up @@ -332,7 +334,7 @@ class LayoutAdapter {
referenceBoundsLength += position.inset(safeAreaInsets)
}
let maxPosition: CGFloat = {
if let maxBounds = anchor.boundingGuide.maxBounds(vc) {
if let maxBounds = anchor.contentBoundingGuide.maxBounds(vc) {
return layout.position.mainLocation(maxBounds.origin)
+ layout.position.mainDimension(maxBounds.size)
} else {
Expand All @@ -345,7 +347,7 @@ class LayoutAdapter {
referenceBoundsLength -= position.inset(safeAreaInsets)
}
let minPosition: CGFloat = {
if let maxBounds = anchor.boundingGuide.maxBounds(vc) {
if let maxBounds = anchor.contentBoundingGuide.maxBounds(vc) {
return layout.position.mainLocation(maxBounds.origin)
} else {
return -(.infinity)
Expand Down Expand Up @@ -645,9 +647,9 @@ class LayoutAdapter {
// The method is separated from prepareLayout(to:) for the rotation support
// It must be called in FloatingPanelController.traitCollectionDidChange(_:)
func updateStaticConstraint() {
NSLayoutConstraint.deactivate([staticConstraint, boundingConstraint].compactMap{ $0 })
NSLayoutConstraint.deactivate([staticConstraint, contentBoundingConstraint].compactMap{ $0 })
staticConstraint = nil
boundingConstraint = nil
contentBoundingConstraint = nil

if vc.contentMode == .fitToBounds {
surfaceView.containerOverflow = 0
Expand All @@ -671,12 +673,12 @@ class LayoutAdapter {
constant = 0.0
}
let baseAnchor = position.mainDimensionAnchor(anchor.contentLayoutGuide)
if let boundingLayoutGuide = anchor.boundingGuide.layoutGuide(vc) {
if let boundingLayoutGuide = anchor.contentBoundingGuide.layoutGuide(vc) {
if anchor.isAbsolute {
boundingConstraint = baseAnchor.constraint(lessThanOrEqualTo: position.mainDimensionAnchor(boundingLayoutGuide),
contentBoundingConstraint = baseAnchor.constraint(lessThanOrEqualTo: position.mainDimensionAnchor(boundingLayoutGuide),
constant: anchor.offset)
} else {
boundingConstraint = baseAnchor.constraint(lessThanOrEqualTo: position.mainDimensionAnchor(boundingLayoutGuide),
contentBoundingConstraint = baseAnchor.constraint(lessThanOrEqualTo: position.mainDimensionAnchor(boundingLayoutGuide),
multiplier: anchor.offset)
}
staticConstraint = surfaceAnchor.constraint(lessThanOrEqualTo: baseAnchor, constant: constant)
Expand All @@ -701,7 +703,7 @@ class LayoutAdapter {
staticConstraint?.identifier = "FloatingPanel-static-width"
}

NSLayoutConstraint.activate([staticConstraint, boundingConstraint].compactMap{ $0 })
NSLayoutConstraint.activate([staticConstraint, contentBoundingConstraint].compactMap{ $0 })

surfaceView.containerOverflow = position.mainDimension(vc.view.bounds.size)
}
Expand Down
61 changes: 29 additions & 32 deletions Sources/LayoutAnchoring.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,73 +162,70 @@ public extension FloatingPanelIntrinsicLayoutAnchor {
/// An object that defines how to settles a panel with a layout guide of a content view.
@objc final public class FloatingPanelAdaptiveLayoutAnchor: NSObject, FloatingPanelLayoutAnchoring /*, NSCopying */ {

/// Returns a layout anchor with the specified offset by an absolute value, layout guide to display content and reference guide for a panel.
/// Returns a layout anchor with the specified offset by an absolute value to display a panel with its intrinsic content size.
///
/// The offset is an amount to offset a position of panel that displays the entire content of the specified guide from an edge of
/// the reference guide. The edge refers to a panel positioning.
///
/// ``contentBoundingGuide`` restricts the content size which a panel displays. For example, given ``referenceGuide`` is `.superview` and ``contentBoundingGuide`` is `.safeArea` for a bottom positioned panel, the panel content is laid out inside the superview of the view of FloatingPanelController(not its safe area), but its content size is limited to its safe area size.
///
/// - Parameters:
/// - absoluteOffset: An absolute offset from the content size in the main dimension(i.e. y axis for a bottom panel) to attach the panel.
/// - contentLayout: The content layout guide to calculate the content size in the panel.
/// - referenceGuide: The rectangular area to lay out the content. If it's set to `.safeArea`, the panel content lays out inside the safe area of its ``FloatingPanelController``'s view.
/// - boundingGuide: The rectangular area to restrict a panel size in the main dimension(i.e. y axis for a bottom panel)
@objc public init(absoluteOffset offset: CGFloat,
contentLayout: UILayoutGuide,
referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea,
boundingGuide: FloatingPanelLayoutBoundingGuide = .none) {
/// - referenceGuide: The rectangular area to lay out the content of a panel. If it's set to `.safeArea`, the panel content displays inside the safe area of its ``FloatingPanelController``'s view. This argument doesn't limit its content size.
/// - contentBoundingGuide: The rectangular area to restrict the content size of a panel in the main dimension(i.e. y axis is the main dimension for a bottom panel).
///
/// - Warning: If ``contentBoundingGuide`` is set to none, the panel may expand out of the screen size, depending on the intrinsic size of its content.
@objc public init(
absoluteOffset offset: CGFloat,
contentLayout: UILayoutGuide,
referenceGuide: FloatingPanelLayoutReferenceGuide,
contentBoundingGuide: FloatingPanelLayoutContentBoundingGuide = .none
) {
self.offset = offset
self.contentLayoutGuide = contentLayout
self.referenceGuide = referenceGuide
self.boundingGuide = boundingGuide
self.contentBoundingGuide = contentBoundingGuide
self.isAbsolute = true
}

/// Returns a layout anchor with the specified offset by a fractional value, layout guide to display content and reference guide for a panel.
/// Returns a layout anchor with the specified offset by a fractional value to display a panel with its intrinsic content size.
///
/// The offset value is a floating-point number in the range 0.0 to 1.0, where 0.0 represents the full content
/// is displayed and 0.5 represents the half of content is displayed.
///
/// ``contentBoundingGuide`` restricts the content size which a panel displays. For example, given ``referenceGuide`` is `.superview` and ``contentBoundingGuide`` is `.safeArea` for a bottom positioned panel, the panel content is laid out inside the superview of the view of FloatingPanelController(not its safe area), but its content size is limited to its safe area size.
///
/// - Parameters:
/// - fractionalOffset: A fractional offset of the content size in the main dimension(i.e. y axis for a bottom panel) to attach the panel.
/// - contentLayout: The content layout guide to calculate the content size in the panel.
/// - referenceGuide: The rectangular area to lay out the content. If it's set to `.safeArea`, the panel content lays out inside the safe area of its ``FloatingPanelController``'s view.
/// - boundingGuide: The rectangular area to restrict a panel size in the main dimension(i.e. y axis for a bottom panel)
@objc public init(fractionalOffset offset: CGFloat,
contentLayout: UILayoutGuide,
referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea,
boundingGuide: FloatingPanelLayoutBoundingGuide = .none) {
/// - referenceGuide: The rectangular area to lay out the content of a panel. If it's set to `.safeArea`, the panel content displays inside the safe area of its ``FloatingPanelController``'s view. This argument doesn't limit its content size.
/// - contentBoundingGuide: The rectangular area to restrict the content size of a panel in the main dimension(i.e. y axis is the main dimension for a bottom panel).
///
/// - Warning: If ``contentBoundingGuide`` is set to none, the panel may expand out of the screen size, depending on the intrinsic size of its content.
@objc public init(
fractionalOffset offset: CGFloat,
contentLayout: UILayoutGuide,
referenceGuide: FloatingPanelLayoutReferenceGuide,
contentBoundingGuide: FloatingPanelLayoutContentBoundingGuide = .none
) {
self.offset = offset
self.contentLayoutGuide = contentLayout
self.referenceGuide = referenceGuide
self.boundingGuide = boundingGuide
self.contentBoundingGuide = contentBoundingGuide
self.isAbsolute = false
}
let offset: CGFloat
let isAbsolute: Bool
let contentLayoutGuide: UILayoutGuide
@objc public let referenceGuide: FloatingPanelLayoutReferenceGuide
@objc public let boundingGuide: FloatingPanelLayoutBoundingGuide
@objc public let contentBoundingGuide: FloatingPanelLayoutContentBoundingGuide
}

public extension FloatingPanelAdaptiveLayoutAnchor {
func layoutConstraints(_ vc: FloatingPanelController, for position: FloatingPanelPosition) -> [NSLayoutConstraint] {
var constraints = [NSLayoutConstraint]()

let boundingConstraint: NSLayoutConstraint
if let boundingLayoutGuide = boundingGuide.layoutGuide(vc) {
switch position {
case .top:
boundingConstraint = vc.surfaceView.bottomAnchor.constraint(greaterThanOrEqualTo: boundingLayoutGuide.bottomAnchor)
case .left:
boundingConstraint = vc.surfaceView.rightAnchor.constraint(greaterThanOrEqualTo: boundingLayoutGuide.rightAnchor)
case .bottom:
boundingConstraint = vc.surfaceView.topAnchor.constraint(greaterThanOrEqualTo: boundingLayoutGuide.topAnchor)
case .right:
boundingConstraint = vc.surfaceView.leftAnchor.constraint(greaterThanOrEqualTo: boundingLayoutGuide.leftAnchor)
}
constraints.append(boundingConstraint)
}

let layoutGuide = referenceGuide.layoutGuide(vc: vc)
let offsetConstraint: NSLayoutConstraint
let offsetAnchor: NSLayoutDimension
Expand Down
8 changes: 4 additions & 4 deletions Sources/LayoutProperties.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension FloatingPanelReferenceEdge {
}
}

/// Constants that specify a layout guide to lay out a panel.
/// A representation to specify a layout guide to lay out a panel.
@objc public enum FloatingPanelLayoutReferenceGuide: Int {
case superview = 0
case safeArea = 1
Expand All @@ -44,14 +44,14 @@ extension FloatingPanelLayoutReferenceGuide {
}
}

/// Constants that specify a layout guide to lay out a panel.
@objc public enum FloatingPanelLayoutBoundingGuide: Int {
/// A representation to specify a bounding box which limit the content size of a panel.
@objc public enum FloatingPanelLayoutContentBoundingGuide: Int {
case none = 0
case superview = 1
case safeArea = 2
}

extension FloatingPanelLayoutBoundingGuide {
extension FloatingPanelLayoutContentBoundingGuide {
func layoutGuide(_ fpc: FloatingPanelController) -> LayoutGuideProvider? {
switch self {
case .superview:
Expand Down

0 comments on commit 04aa5b5

Please sign in to comment.