Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc1e2668cc | |||
| da31639068 | |||
| 5fa37b4371 | |||
| 0de380b79e | |||
| 8a194d70e8 | |||
| 874d0c68f8 | |||
| d0c1e00388 | |||
| 93168c217a | |||
| 28e6b74714 | |||
| f9bf9af179 | |||
| d89223819c | |||
| 7b7e8a8365 | |||
| 476f45deac | |||
| d1f769dd7e | |||
| a629cf0789 | |||
| 66c6aab497 | |||
| ca22dd3283 | |||
| e666333b0f |
@@ -3,6 +3,7 @@
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
@MainActor
|
||||
final class UseCaseController: NSObject {
|
||||
unowned let mainVC: MainViewController
|
||||
private(set) var useCase: UseCase
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -475,6 +475,19 @@
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
|
||||
SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY = YES;
|
||||
SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES;
|
||||
SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES;
|
||||
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -494,7 +507,7 @@
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -505,6 +518,19 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
|
||||
SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY = YES;
|
||||
SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES;
|
||||
SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES;
|
||||
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -631,7 +657,7 @@
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
@@ -644,6 +670,19 @@
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "TEST DEBUG FP_LOG";
|
||||
SWIFT_COMPILATION_MODE = singlefile;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_STRICT_CONCURRENCY = complete;
|
||||
SWIFT_UPCOMING_FEATURE_CONCISE_MAGIC_FILE = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DEPRECATE_APPLICATION_MAIN = YES;
|
||||
SWIFT_UPCOMING_FEATURE_DISABLE_OUTWARD_ACTOR_ISOLATION = YES;
|
||||
SWIFT_UPCOMING_FEATURE_EXISTENTIAL_ANY = YES;
|
||||
SWIFT_UPCOMING_FEATURE_FORWARD_TRAILING_CLOSURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_GLOBAL_CONCURRENCY = YES;
|
||||
SWIFT_UPCOMING_FEATURE_IMPLICIT_OPEN_EXISTENTIALS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_IMPORT_OBJC_FORWARD_DECLS = YES;
|
||||
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_INTERNAL_IMPORTS_BY_DEFAULT = YES;
|
||||
SWIFT_UPCOMING_FEATURE_ISOLATED_DEFAULT_VALUES = YES;
|
||||
SWIFT_UPCOMING_FEATURE_REGION_BASED_ISOLATION = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
||||
@@ -86,9 +86,9 @@ open class FloatingPanelDefaultBehavior: FloatingPanelBehavior {
|
||||
|
||||
class BehaviorAdapter {
|
||||
unowned let vc: FloatingPanelController
|
||||
fileprivate var behavior: FloatingPanelBehavior
|
||||
fileprivate var behavior: any FloatingPanelBehavior
|
||||
|
||||
init(vc: FloatingPanelController, behavior: FloatingPanelBehavior) {
|
||||
init(vc: FloatingPanelController, behavior: any FloatingPanelBehavior) {
|
||||
self.vc = vc
|
||||
self.behavior = behavior
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class BehaviorAdapter {
|
||||
}
|
||||
|
||||
extension FloatingPanelController {
|
||||
var _behavior: FloatingPanelBehavior {
|
||||
var _behavior: any FloatingPanelBehavior {
|
||||
get { floatingPanel.behaviorAdapter.behavior }
|
||||
set { floatingPanel.behaviorAdapter.behavior = newValue}
|
||||
}
|
||||
|
||||
+21
-18
@@ -6,14 +6,15 @@ import os.log
|
||||
/// A set of methods implemented by the delegate of a panel controller allows the adopting delegate to respond to
|
||||
/// messages from the FloatingPanelController class and thus respond to, and in some affect, operations such as
|
||||
/// dragging, attracting a panel, layout of a panel and the content, and transition animations.
|
||||
@MainActor
|
||||
@objc public protocol FloatingPanelControllerDelegate {
|
||||
/// Returns a FloatingPanelLayout object. If you use the default one, you can use a `FloatingPanelBottomLayout` object.
|
||||
@objc(floatingPanel:layoutForTraitCollection:) optional
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> any FloatingPanelLayout
|
||||
|
||||
/// Returns a FloatingPanelLayout object. If you use the default one, you can use a `FloatingPanelBottomLayout` object.
|
||||
@objc(floatingPanel:layoutForSize:) optional
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> FloatingPanelLayout
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> any FloatingPanelLayout
|
||||
|
||||
/// Returns a UIViewPropertyAnimator object to add/present the panel to a position.
|
||||
///
|
||||
@@ -150,7 +151,7 @@ open class FloatingPanelController: UIViewController {
|
||||
|
||||
/// The delegate of a panel controller object.
|
||||
@objc
|
||||
public weak var delegate: FloatingPanelControllerDelegate?{
|
||||
public weak var delegate: (any FloatingPanelControllerDelegate)?{
|
||||
didSet{
|
||||
didUpdateDelegate()
|
||||
}
|
||||
@@ -198,7 +199,7 @@ open class FloatingPanelController: UIViewController {
|
||||
/// You need to call ``invalidateLayout()`` if you want to apply a new layout object into the panel
|
||||
/// immediately.
|
||||
@objc
|
||||
public var layout: FloatingPanelLayout {
|
||||
public var layout: any FloatingPanelLayout {
|
||||
get { _layout }
|
||||
set {
|
||||
_layout = newValue
|
||||
@@ -211,7 +212,7 @@ open class FloatingPanelController: UIViewController {
|
||||
|
||||
/// The behavior object that the controller manages
|
||||
@objc
|
||||
public var behavior: FloatingPanelBehavior {
|
||||
public var behavior: any FloatingPanelBehavior {
|
||||
get { _behavior }
|
||||
set {
|
||||
_behavior = newValue
|
||||
@@ -282,7 +283,7 @@ open class FloatingPanelController: UIViewController {
|
||||
|
||||
/// Initialize a newly created panel controller.
|
||||
@objc
|
||||
public init(delegate: FloatingPanelControllerDelegate? = nil) {
|
||||
public init(delegate: (any FloatingPanelControllerDelegate)? = nil) {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
self.delegate = delegate
|
||||
setUp()
|
||||
@@ -294,7 +295,7 @@ open class FloatingPanelController: UIViewController {
|
||||
modalPresentationStyle = .custom
|
||||
transitioningDelegate = modalTransition
|
||||
|
||||
let initialLayout: FloatingPanelLayout
|
||||
let initialLayout: any FloatingPanelLayout
|
||||
if let layout = delegate?.floatingPanel?(self, layoutFor: traitCollection) {
|
||||
initialLayout = layout
|
||||
} else {
|
||||
@@ -344,7 +345,7 @@ open class FloatingPanelController: UIViewController {
|
||||
floatingPanel.adjustScrollContentInsetIfNeeded()
|
||||
}
|
||||
|
||||
open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
open override func viewWillTransition(to size: CGSize, with coordinator: any UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
|
||||
if self.view.bounds.size == size {
|
||||
@@ -363,7 +364,7 @@ open class FloatingPanelController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
open override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
open override func willTransition(to newCollection: UITraitCollection, with coordinator: any UIViewControllerTransitionCoordinator) {
|
||||
super.willTransition(to: newCollection, with: coordinator)
|
||||
|
||||
if shouldUpdateLayout(from: traitCollection, to: newCollection) == false {
|
||||
@@ -483,16 +484,18 @@ open class FloatingPanelController: UIViewController {
|
||||
// 2. The safe area top inset can be variable on the large title navigation bar(iOS11+).
|
||||
// That's why it needs the observation to keep `adjustedContentInsets` correct.
|
||||
safeAreaInsetsObservation = self.view.observe(\.safeAreaInsets, options: [.initial, .new, .old]) { [weak self] (_, change) in
|
||||
// Use `self.view.safeAreaInsets` because `change.newValue` can be nil in particular case when
|
||||
// is reported in https://github.com/SCENEE/FloatingPanel/issues/330
|
||||
guard let self = self, change.oldValue != self.view.safeAreaInsets else { return }
|
||||
MainActor.assumeIsolated {
|
||||
// Use `self.view.safeAreaInsets` because `change.newValue` can be nil in particular case when
|
||||
// is reported in https://github.com/SCENEE/FloatingPanel/issues/330
|
||||
guard let self = self, change.oldValue != self.view.safeAreaInsets else { return }
|
||||
|
||||
// Sometimes the bounding rectangle of the controlled view becomes invalid when the screen is rotated.
|
||||
// This results in its safeAreaInsets change. In that case, `self.update(safeAreaInsets:)` leads
|
||||
// an unsatisfied constraints error. So this method should not be called with those bounds.
|
||||
guard self.view.bounds.height > 0 && self.view.bounds.width > 0 else { return }
|
||||
// Sometimes the bounding rectangle of the controlled view becomes invalid when the screen is rotated.
|
||||
// This results in its safeAreaInsets change. In that case, `self.update(safeAreaInsets:)` leads
|
||||
// an unsatisfied constraints error. So this method should not be called with those bounds.
|
||||
guard self.view.bounds.height > 0 && self.view.bounds.width > 0 else { return }
|
||||
|
||||
self.update(safeAreaInsets: self.view.safeAreaInsets)
|
||||
self.update(safeAreaInsets: self.view.safeAreaInsets)
|
||||
}
|
||||
}
|
||||
|
||||
move(to: floatingPanel.layoutAdapter.initialState,
|
||||
@@ -729,7 +732,7 @@ extension FloatingPanelController {
|
||||
|
||||
// MARK: - Swizzling
|
||||
|
||||
private var originalDismissImp: IMP?
|
||||
@MainActor private var originalDismissImp: IMP?
|
||||
private typealias DismissFunction = @convention(c) (AnyObject, Selector, Bool, (() -> Void)?) -> Void
|
||||
extension FloatingPanelController {
|
||||
private static let dismissSwizzling: Void = {
|
||||
|
||||
+6
-8
@@ -3,7 +3,6 @@
|
||||
import UIKit
|
||||
import os.log
|
||||
|
||||
///
|
||||
/// The presentation model of FloatingPanel
|
||||
///
|
||||
class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
@@ -79,7 +78,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
// MARK: - Interface
|
||||
|
||||
init(_ vc: FloatingPanelController, layout: FloatingPanelLayout, behavior: FloatingPanelBehavior) {
|
||||
init(_ vc: FloatingPanelController, layout: any FloatingPanelLayout, behavior: any FloatingPanelBehavior) {
|
||||
ownerVC = vc
|
||||
|
||||
surfaceView = SurfaceView()
|
||||
@@ -114,8 +113,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
deinit {
|
||||
// Release `NumericSpringAnimator.displayLink` from the run loop.
|
||||
self.moveAnimator?.stopAnimation(false)
|
||||
moveAnimator?.stopAnimation(false)
|
||||
}
|
||||
|
||||
func move(to: FloatingPanelState, animated: Bool, completion: (() -> Void)? = nil) {
|
||||
@@ -1247,7 +1245,7 @@ public final class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer {
|
||||
///
|
||||
/// - Note: The delegate is used by FloatingPanel itself. If you set your own delegate object, an
|
||||
/// exception is raised. If you want to handle the methods of UIGestureRecognizerDelegate, you can use `delegateProxy`.
|
||||
public override weak var delegate: UIGestureRecognizerDelegate? {
|
||||
public override weak var delegate: (any UIGestureRecognizerDelegate)? {
|
||||
get {
|
||||
return super.delegate
|
||||
}
|
||||
@@ -1268,7 +1266,7 @@ public final class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer {
|
||||
/// The default object implementing a set methods of the delegate of the gesture recognizer.
|
||||
///
|
||||
/// Use this property with ``delegateProxy`` when you need to use the default gesture behaviors in a proxy implementation.
|
||||
public var delegateOrigin: UIGestureRecognizerDelegate {
|
||||
public var delegateOrigin: any UIGestureRecognizerDelegate {
|
||||
return floatingPanel
|
||||
}
|
||||
|
||||
@@ -1276,7 +1274,7 @@ public final class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer {
|
||||
///
|
||||
/// `UIGestureRecognizerDelegate` methods implementing by this object are called instead of the default delegate,
|
||||
/// ``delegateOrigin``.
|
||||
public weak var delegateProxy: UIGestureRecognizerDelegate? {
|
||||
public weak var delegateProxy: (any UIGestureRecognizerDelegate)? {
|
||||
didSet {
|
||||
self.delegate = floatingPanel?.panGestureDelegateRouter // Update the cached IMP
|
||||
}
|
||||
@@ -1309,7 +1307,7 @@ public final class FloatingPanelPanGestureRecognizer: UIPanGestureRecognizer {
|
||||
|
||||
// MARK: - Animator
|
||||
|
||||
private class NumericSpringAnimator: NSObject {
|
||||
private final class NumericSpringAnimator: NSObject, @unchecked Sendable {
|
||||
struct Data {
|
||||
let value: CGFloat
|
||||
let velocity: CGFloat
|
||||
|
||||
@@ -36,6 +36,7 @@ extension CGPoint {
|
||||
|
||||
// MARK: - UIKit
|
||||
|
||||
@MainActor
|
||||
protocol LayoutGuideProvider {
|
||||
var topAnchor: NSLayoutYAxisAnchor { get }
|
||||
var leftAnchor: NSLayoutXAxisAnchor { get }
|
||||
|
||||
+10
-8
@@ -4,6 +4,7 @@ import UIKit
|
||||
import os.log
|
||||
|
||||
/// An interface for generating layout information for a panel.
|
||||
@MainActor
|
||||
@objc public protocol FloatingPanelLayout {
|
||||
/// Returns the position of a panel in a `FloatingPanelController` view .
|
||||
@objc var position: FloatingPanelPosition { get }
|
||||
@@ -12,7 +13,7 @@ import os.log
|
||||
@objc var initialState: FloatingPanelState { get }
|
||||
|
||||
/// Returns the layout anchors to specify the snapping locations for each state.
|
||||
@objc var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] { get }
|
||||
@objc var anchors: [FloatingPanelState: any FloatingPanelLayoutAnchoring] { get }
|
||||
|
||||
/// Returns layout constraints to determine the cross dimension of a panel.
|
||||
@objc optional func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint]
|
||||
@@ -31,7 +32,7 @@ open class FloatingPanelBottomLayout: NSObject, FloatingPanelLayout {
|
||||
return .half
|
||||
}
|
||||
|
||||
open var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
open var anchors: [FloatingPanelState: any FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
@@ -60,11 +61,12 @@ struct LayoutSegment {
|
||||
let upper: FloatingPanelState?
|
||||
}
|
||||
|
||||
@MainActor
|
||||
class LayoutAdapter {
|
||||
private unowned var vc: FloatingPanelController
|
||||
private let defaultLayout = FloatingPanelBottomLayout()
|
||||
|
||||
fileprivate var layout: FloatingPanelLayout {
|
||||
fileprivate var layout: any FloatingPanelLayout {
|
||||
didSet {
|
||||
surfaceView.position = position
|
||||
}
|
||||
@@ -287,7 +289,7 @@ class LayoutAdapter {
|
||||
return offset.rounded(by: surfaceView.fp_displayScale)
|
||||
}
|
||||
|
||||
private var hiddenAnchor: FloatingPanelLayoutAnchoring {
|
||||
private var hiddenAnchor: any FloatingPanelLayoutAnchoring {
|
||||
switch position {
|
||||
case .top:
|
||||
return FloatingPanelLayoutAnchor(absoluteInset: -100, edge: .top, referenceGuide: .superview)
|
||||
@@ -300,7 +302,7 @@ class LayoutAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
init(vc: FloatingPanelController, layout: FloatingPanelLayout) {
|
||||
init(vc: FloatingPanelController, layout: any FloatingPanelLayout) {
|
||||
self.vc = vc
|
||||
self.layout = layout
|
||||
}
|
||||
@@ -404,7 +406,7 @@ class LayoutAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private func referenceEdge(of anchor: FloatingPanelLayoutAnchoring) -> FloatingPanelReferenceEdge {
|
||||
private func referenceEdge(of anchor: any FloatingPanelLayoutAnchoring) -> FloatingPanelReferenceEdge {
|
||||
switch anchor {
|
||||
case is FloatingPanelIntrinsicLayoutAnchor,
|
||||
is FloatingPanelAdaptiveLayoutAnchor:
|
||||
@@ -546,7 +548,7 @@ class LayoutAdapter {
|
||||
NSLayoutConstraint.deactivate(constraint: interactionConstraint)
|
||||
interactionConstraint = nil
|
||||
|
||||
let layoutGuideProvider: LayoutGuideProvider
|
||||
let layoutGuideProvider: any LayoutGuideProvider
|
||||
switch anchor.referenceGuide {
|
||||
case .safeArea:
|
||||
layoutGuideProvider = vc.view.safeAreaLayoutGuide
|
||||
@@ -854,7 +856,7 @@ extension LayoutAdapter {
|
||||
}
|
||||
|
||||
extension FloatingPanelController {
|
||||
var _layout: FloatingPanelLayout {
|
||||
var _layout: any FloatingPanelLayout {
|
||||
get {
|
||||
floatingPanel.layoutAdapter.layout
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import UIKit
|
||||
|
||||
/// An interface for implementing custom layout anchor objects.
|
||||
@MainActor
|
||||
@objc public protocol FloatingPanelLayoutAnchoring {
|
||||
var referenceGuide: FloatingPanelLayoutReferenceGuide { get }
|
||||
func layoutConstraints(_ fpc: FloatingPanelController, for position: FloatingPanelPosition) -> [NSLayoutConstraint]
|
||||
@@ -17,7 +18,7 @@ import UIKit
|
||||
/// positioning.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - absoluteOffset: An absolute offset to attach the panel from the edge.
|
||||
/// - absoluteInset: An absolute offset to attach the panel from the edge.
|
||||
/// - edge: Specify the edge of ``FloatingPanelController``'s view. This is the staring point of the offset.
|
||||
/// - 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.
|
||||
@objc public init(absoluteInset: CGFloat, edge: FloatingPanelReferenceEdge, referenceGuide: FloatingPanelLayoutReferenceGuide) {
|
||||
@@ -34,7 +35,7 @@ import UIKit
|
||||
/// 1.0 represents a distance to the opposite edge.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - fractionalOffset: A fractional value of the size of ``FloatingPanelController``'s view to attach the panel from the edge.
|
||||
/// - fractionalInset: A fractional value of the size of ``FloatingPanelController``'s view to attach the panel from the edge.
|
||||
/// - edge: Specify the edge of ``FloatingPanelController``'s view. This is the staring point of the offset.
|
||||
/// - 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.
|
||||
@objc public init(fractionalInset: CGFloat, edge: FloatingPanelReferenceEdge, referenceGuide: FloatingPanelLayoutReferenceGuide) {
|
||||
@@ -65,7 +66,7 @@ public extension FloatingPanelLayoutAnchor {
|
||||
}
|
||||
}
|
||||
|
||||
private func layoutConstraints(_ layoutGuide: LayoutGuideProvider, for edgeAnchor: NSLayoutYAxisAnchor) -> [NSLayoutConstraint] {
|
||||
private func layoutConstraints(_ layoutGuide: any LayoutGuideProvider, for edgeAnchor: NSLayoutYAxisAnchor) -> [NSLayoutConstraint] {
|
||||
switch referenceEdge {
|
||||
case .top:
|
||||
if isAbsolute {
|
||||
@@ -84,7 +85,7 @@ public extension FloatingPanelLayoutAnchor {
|
||||
}
|
||||
}
|
||||
|
||||
private func layoutConstraints(_ layoutGuide: LayoutGuideProvider, for edgeAnchor: NSLayoutXAxisAnchor) -> [NSLayoutConstraint] {
|
||||
private func layoutConstraints(_ layoutGuide: any LayoutGuideProvider, for edgeAnchor: NSLayoutXAxisAnchor) -> [NSLayoutConstraint] {
|
||||
switch referenceEdge {
|
||||
case .left:
|
||||
if isAbsolute {
|
||||
@@ -115,8 +116,8 @@ public extension FloatingPanelLayoutAnchor {
|
||||
/// - 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.
|
||||
/// - 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.
|
||||
@objc public init(absoluteOffset offset: CGFloat, referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea) {
|
||||
self.offset = offset
|
||||
@objc public init(absoluteOffset: CGFloat, referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea) {
|
||||
self.offset = absoluteOffset
|
||||
self.referenceGuide = referenceGuide
|
||||
self.isAbsolute = true
|
||||
}
|
||||
@@ -129,8 +130,8 @@ public extension FloatingPanelLayoutAnchor {
|
||||
/// - 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.
|
||||
/// - 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.
|
||||
@objc public init(fractionalOffset offset: CGFloat, referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea) {
|
||||
self.offset = offset
|
||||
@objc public init(fractionalOffset: CGFloat, referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea) {
|
||||
self.offset = fractionalOffset
|
||||
self.referenceGuide = referenceGuide
|
||||
self.isAbsolute = false
|
||||
}
|
||||
@@ -177,12 +178,12 @@ public extension FloatingPanelIntrinsicLayoutAnchor {
|
||||
///
|
||||
/// - 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,
|
||||
absoluteOffset: CGFloat,
|
||||
contentLayout: UILayoutGuide,
|
||||
referenceGuide: FloatingPanelLayoutReferenceGuide,
|
||||
contentBoundingGuide: FloatingPanelLayoutContentBoundingGuide = .none
|
||||
) {
|
||||
self.offset = offset
|
||||
self.offset = absoluteOffset
|
||||
self.contentLayoutGuide = contentLayout
|
||||
self.referenceGuide = referenceGuide
|
||||
self.contentBoundingGuide = contentBoundingGuide
|
||||
@@ -204,12 +205,12 @@ public extension FloatingPanelIntrinsicLayoutAnchor {
|
||||
///
|
||||
/// - 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,
|
||||
fractionalOffset: CGFloat,
|
||||
contentLayout: UILayoutGuide,
|
||||
referenceGuide: FloatingPanelLayoutReferenceGuide,
|
||||
contentBoundingGuide: FloatingPanelLayoutContentBoundingGuide = .none
|
||||
) {
|
||||
self.offset = offset
|
||||
self.offset = fractionalOffset
|
||||
self.contentLayoutGuide = contentLayout
|
||||
self.referenceGuide = referenceGuide
|
||||
self.contentBoundingGuide = contentBoundingGuide
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import UIKit
|
||||
|
||||
/// Constants that specify the edge of the container of a panel.
|
||||
@MainActor
|
||||
@objc public enum FloatingPanelReferenceEdge: Int {
|
||||
case top
|
||||
case left
|
||||
@@ -28,13 +29,14 @@ extension FloatingPanelReferenceEdge {
|
||||
}
|
||||
|
||||
/// A representation to specify a rectangular area to lay out a panel.
|
||||
@MainActor
|
||||
@objc public enum FloatingPanelLayoutReferenceGuide: Int {
|
||||
case superview = 0
|
||||
case safeArea = 1
|
||||
}
|
||||
|
||||
extension FloatingPanelLayoutReferenceGuide {
|
||||
func layoutGuide(vc: UIViewController) -> LayoutGuideProvider {
|
||||
func layoutGuide(vc: UIViewController) -> any LayoutGuideProvider {
|
||||
switch self {
|
||||
case .safeArea:
|
||||
return vc.view.safeAreaLayoutGuide
|
||||
@@ -45,6 +47,7 @@ extension FloatingPanelLayoutReferenceGuide {
|
||||
}
|
||||
|
||||
/// A representation to specify a bounding box which limit the content size of a panel.
|
||||
@MainActor
|
||||
@objc public enum FloatingPanelLayoutContentBoundingGuide: Int {
|
||||
case none = 0
|
||||
case superview = 1
|
||||
@@ -52,7 +55,7 @@ extension FloatingPanelLayoutReferenceGuide {
|
||||
}
|
||||
|
||||
extension FloatingPanelLayoutContentBoundingGuide {
|
||||
func layoutGuide(_ fpc: FloatingPanelController) -> LayoutGuideProvider? {
|
||||
func layoutGuide(_ fpc: FloatingPanelController) -> (any LayoutGuideProvider)? {
|
||||
switch self {
|
||||
case .superview:
|
||||
return fpc.view
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
import os.log
|
||||
|
||||
let msg = StaticString("%{public}@")
|
||||
let sysLog = OSLog(subsystem: Logging.subsystem, category: Logging.category)
|
||||
nonisolated(unsafe) let sysLog = OSLog(subsystem: Logging.subsystem, category: Logging.category)
|
||||
#if FP_LOG
|
||||
let devLog = OSLog(subsystem: Logging.subsystem, category: "\(Logging.category):dev")
|
||||
#else
|
||||
let devLog = OSLog.disabled
|
||||
nonisolated(unsafe) let devLog = OSLog.disabled
|
||||
#endif
|
||||
|
||||
struct Logging {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import UIKit
|
||||
|
||||
/// Constants describing the position of a panel in a screen
|
||||
@MainActor
|
||||
@objc public enum FloatingPanelPosition: Int {
|
||||
case top
|
||||
case left
|
||||
@@ -25,7 +26,7 @@ extension FloatingPanelPosition {
|
||||
}
|
||||
}
|
||||
|
||||
func mainDimensionAnchor(_ layoutGuide: LayoutGuideProvider) -> NSLayoutDimension {
|
||||
func mainDimensionAnchor(_ layoutGuide: any LayoutGuideProvider) -> NSLayoutDimension {
|
||||
switch self {
|
||||
case .top, .bottom: return layoutGuide.heightAnchor
|
||||
case .left, .right: return layoutGuide.widthAnchor
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import Foundation
|
||||
|
||||
/// An object that represents the display state of a panel in a screen.
|
||||
@objc
|
||||
open class FloatingPanelState: NSObject, NSCopying, RawRepresentable {
|
||||
public final class FloatingPanelState: NSObject, NSCopying, RawRepresentable, Sendable {
|
||||
public typealias RawValue = String
|
||||
|
||||
required public init?(rawValue: RawValue) {
|
||||
|
||||
@@ -5,11 +5,11 @@ import UIKit
|
||||
class ModalTransition: NSObject, UIViewControllerTransitioningDelegate {
|
||||
func animationController(forPresented presented: UIViewController,
|
||||
presenting: UIViewController,
|
||||
source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
source: UIViewController) -> (any UIViewControllerAnimatedTransitioning)? {
|
||||
return ModalPresentTransition()
|
||||
}
|
||||
|
||||
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
func animationController(forDismissed dismissed: UIViewController) -> (any UIViewControllerAnimatedTransitioning)? {
|
||||
return ModalDismissTransition()
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ class PresentationController: UIPresentationController {
|
||||
}
|
||||
|
||||
class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
func transitionDuration(using transitionContext: (any UIViewControllerContextTransitioning)?) -> TimeInterval {
|
||||
guard
|
||||
let fpc = transitionContext?.viewController(forKey: .to) as? FloatingPanelController
|
||||
else { fatalError()}
|
||||
@@ -90,7 +90,7 @@ class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
return TimeInterval(animator.duration)
|
||||
}
|
||||
|
||||
func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
|
||||
func interruptibleAnimator(using transitionContext: any UIViewControllerContextTransitioning) -> any UIViewImplicitlyAnimating {
|
||||
guard
|
||||
let fpc = transitionContext.viewController(forKey: .to) as? FloatingPanelController
|
||||
else { fatalError() }
|
||||
@@ -110,13 +110,13 @@ class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
return transitionAnimator
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
func animateTransition(using transitionContext: any UIViewControllerContextTransitioning) {
|
||||
self.interruptibleAnimator(using: transitionContext).startAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
class ModalDismissTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
func transitionDuration(using transitionContext: (any UIViewControllerContextTransitioning)?) -> TimeInterval {
|
||||
guard
|
||||
let fpc = transitionContext?.viewController(forKey: .from) as? FloatingPanelController
|
||||
else { fatalError()}
|
||||
@@ -125,7 +125,7 @@ class ModalDismissTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
return TimeInterval(animator.duration)
|
||||
}
|
||||
|
||||
func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
|
||||
func interruptibleAnimator(using transitionContext: any UIViewControllerContextTransitioning) -> any UIViewImplicitlyAnimating {
|
||||
guard
|
||||
let fpc = transitionContext.viewController(forKey: .from) as? FloatingPanelController
|
||||
else { fatalError() }
|
||||
@@ -142,7 +142,7 @@ class ModalDismissTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
return fpc.transitionAnimator!
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
func animateTransition(using transitionContext: any UIViewControllerContextTransitioning) {
|
||||
self.interruptibleAnimator(using: transitionContext).startAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user