Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a917d6a626 | |||
| 7511ce577d | |||
| e7d0a72440 | |||
| 44923ef66e | |||
| 2760bc7298 | |||
| d428e96b03 | |||
| 67495961e5 | |||
| 7b88703e43 | |||
| c40e66ef3d | |||
| 53fb131d0e | |||
| 37969f6cb3 | |||
| a0ba3af012 | |||
| 6082dba6a7 | |||
| 43327e8123 | |||
| 0a5bc19d0f | |||
| dd52e1eaee | |||
| 22aa055843 | |||
| 448fc5cbb4 | |||
| b4fe3b408c | |||
| 6ecc7924ba | |||
| 0b82902233 | |||
| 597dbd4145 | |||
| 1ee949ff1b | |||
| 2a29cb5b3e | |||
| 208ab665da | |||
| 3e20314cfa | |||
| 5b8e9a54d9 | |||
| d3c30b35d9 | |||
| 8bb3795931 | |||
| 9383cd001d | |||
| 6d5f770066 | |||
| ce2cafed5b | |||
| 68352218ac | |||
| e3736e4214 | |||
| d6bbf92339 | |||
| 0e833aee3c | |||
| 5949bc88ea | |||
| 30bd261a10 | |||
| f92279484f | |||
| 2205d1186d | |||
| cd0948a9a4 | |||
| 6589aff4ac | |||
| d34c16b1a5 | |||
| 05813253f9 | |||
| 4ab7d26030 | |||
| 162545d7e9 | |||
| 4904ea19cb | |||
| b941f91556 | |||
| f917316135 | |||
| 6235a19588 | |||
| c47fc3d1d5 | |||
| e6d285c6df | |||
| a26a6beab2 | |||
| b00a05b9ed | |||
| bfbb7ad004 | |||
| 4dd52b1790 | |||
| aef914e0fd | |||
| 2ef35f58a3 | |||
| 8aaf8b7b25 | |||
| c330b59a9f | |||
| 639e4221e8 | |||
| 1ff3c28de8 | |||
| 89092676e3 | |||
| bacc871dd2 | |||
| 0bc9812c23 | |||
| a4d98971b3 | |||
| 1b0ec64489 | |||
| 345e894007 | |||
| 1fb1708df9 | |||
| b9edbf766e | |||
| fe30e60235 | |||
| 6e7c31110f | |||
| e39f634d34 | |||
| 5851fd77c4 |
@@ -0,0 +1,21 @@
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
test-ios14_5-iPhone_12_Pro:
|
||||
macos:
|
||||
xcode: 13.4.1
|
||||
steps:
|
||||
- checkout
|
||||
- run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=14.5,name=iPhone 12 Pro'
|
||||
test-ios13_7-iPhone_11_Pro:
|
||||
macos:
|
||||
xcode: 12.5.1
|
||||
steps:
|
||||
- checkout
|
||||
- run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=13.7,name=iPhone 11 Pro'
|
||||
|
||||
workflows:
|
||||
test:
|
||||
jobs:
|
||||
- test-ios14_5-iPhone_12_Pro
|
||||
- test-ios13_7-iPhone_11_Pro
|
||||
+83
-69
@@ -10,94 +10,108 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macOS-11
|
||||
runs-on: ${{ matrix.runsOn }}
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- swift: "5.8"
|
||||
xcode: "14.3"
|
||||
runsOn: macos-13
|
||||
- swift: "5.7"
|
||||
xcode: "14.1"
|
||||
runsOn: macos-12
|
||||
- swift: "5.6"
|
||||
xcode: "13.4.1"
|
||||
runsOn: macos-12
|
||||
- swift: "5.5"
|
||||
xcode: "13.2.1"
|
||||
runsOn: macos-11
|
||||
- swift: "5.4"
|
||||
xcode: "12.5.1"
|
||||
runsOn: macos-11
|
||||
- swift: "5.3"
|
||||
xcode: "12.4"
|
||||
runsOn: macos-11
|
||||
- swift: "5.2"
|
||||
xcode: "11.7"
|
||||
runsOn: macos-11
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Swift 5.4"
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=5.4 clean build
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_12.5.1.app/Contents/Developer
|
||||
- name: "Swift 5.5"
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=5.5 clean build
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer
|
||||
- uses: actions/checkout@v3
|
||||
- name: Building in Swift ${{ matrix.swift }}
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=${{ matrix.swift }} clean build
|
||||
|
||||
build_compat:
|
||||
runs-on: macOS-10.15
|
||||
test:
|
||||
runs-on: ${{ matrix.runsOn }}
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: "16.1"
|
||||
xcode: "14.1"
|
||||
sim: "iPhone 14 Pro"
|
||||
runsOn: macos-12
|
||||
- os: "15.5"
|
||||
xcode: "13.4.1"
|
||||
sim: "iPhone 13 Pro"
|
||||
runsOn: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Swift 5.1"
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=5.1 clean build
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.3.1.app/Contents/Developer
|
||||
- name: "Swift 5.2"
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=5.2 clean build
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.7.app/Contents/Developer
|
||||
- name: "Swift 5.3"
|
||||
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=5.3 clean build
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer
|
||||
|
||||
testing:
|
||||
runs-on: macOS-11
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Testing in iOS 14.5"
|
||||
run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=14.5,name=iPhone 12 Pro'
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_12.5.1.app/Contents/Developer
|
||||
- name: "Testing in iOS 15.0"
|
||||
run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=15.0,name=iPhone 13 Pro'
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer
|
||||
|
||||
testing_compat:
|
||||
runs-on: macOS-10.15
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Testing in iOS 13.7"
|
||||
run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=13.7,name=iPhone 11 Pro'
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.7.app/Contents/Developer
|
||||
- name: "Testing in iOS 14.4"
|
||||
run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=14.4,name=iPhone 12 Pro'
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer
|
||||
- uses: actions/checkout@v3
|
||||
- name: Testing in iOS ${{ matrix.os }}
|
||||
run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=${{ matrix.os }},name=${{ matrix.sim }}'
|
||||
timeout-minutes: 20
|
||||
|
||||
example:
|
||||
runs-on: macOS-11
|
||||
runs-on: macos-12
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer
|
||||
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- example: "Maps"
|
||||
- example: "Maps-SwiftUI"
|
||||
- example: "Stocks"
|
||||
- example: "Samples"
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Build Maps"
|
||||
run: xcodebuild -workspace FloatingPanel.xcworkspace -scheme Maps -sdk iphonesimulator clean build
|
||||
- name: "Build Stocks"
|
||||
run: xcodebuild -workspace FloatingPanel.xcworkspace -scheme Stocks -sdk iphonesimulator clean build
|
||||
- name: "Build Samples"
|
||||
run: xcodebuild -workspace FloatingPanel.xcworkspace -scheme Samples -sdk iphonesimulator clean build
|
||||
- uses: actions/checkout@v3
|
||||
- name: Building ${{ matrix.example }}
|
||||
run: xcodebuild -workspace FloatingPanel.xcworkspace -scheme ${{ matrix.example }} -sdk iphonesimulator clean build
|
||||
|
||||
swiftpm:
|
||||
runs-on: macOS-11
|
||||
runs-on: macos-12
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer
|
||||
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# 15.7
|
||||
- target: "x86_64-apple-ios15.7-simulator"
|
||||
- target: "arm64-apple-ios15.7-simulator"
|
||||
# 16.1
|
||||
- target: "x86_64-apple-ios16.1-simulator"
|
||||
- target: "arm64-apple-ios16.1-simulator"
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Swift Package build"
|
||||
run: swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios14.3-simulator"
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Swift Package Manager build"
|
||||
run: swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "${{ matrix.target }}"
|
||||
|
||||
carthage:
|
||||
runs-on: macOS-11
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Carthage build"
|
||||
run: carthage build --use-xcframeworks --no-skip-current
|
||||
|
||||
cocoapods:
|
||||
runs-on: macOS-11
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v3
|
||||
- name: "CocoaPods: pod lib lint"
|
||||
run: pod lib lint --allow-warnings
|
||||
- name: "CocoaPods: pod spec lint"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
version: 1
|
||||
builder:
|
||||
configs:
|
||||
- documentation_targets: [FloatingPanel]
|
||||
platform: ios
|
||||
@@ -1,3 +0,0 @@
|
||||
--header "// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license."
|
||||
--disable andOperator,anyObjectProtocol,blankLinesAroundMark,blankLinesAtEndOfScope,blankLinesAtStartOfScope,blankLinesBetweenScopes,braces,consecutiveBlankLines,consecutiveSpaces,duplicateImports,elseOnSameLine,emptyBraces,hoistPatternLet,indent,isEmpty,leadingDelimiters,linebreakAtEndOfFile,linebreaks,numberFormatting,redundantBackticks,redundantBreak,redundantExtensionACL,redundantFileprivate,redundantGet,redundantInit,redundantLet,redundantLetError,redundantNilInit,redundantObjc,redundantParens,redundantPattern,redundantRawValues,redundantReturn,redundantSelf,redundantVoidReturnType,semicolons,sortedImports,spaceAroundBraces,spaceAroundBrackets,spaceAroundComments,spaceAroundGenerics,spaceAroundOperators,spaceAroundParens,spaceInsideBraces,spaceInsideBrackets,spaceInsideComments,spaceInsideGenerics,spaceInsideParens,specifiers,strongOutlets,strongifiedSelf,todos,trailingClosures,trailingCommas,trailingSpace,typeSugar,unusedArguments,void,wrapArguments,yodaConditions
|
||||
|
||||
@@ -96,8 +96,20 @@ struct FloatingPanelView<Content: View, FloatingPanelContent: View>: UIViewContr
|
||||
ignoresKeyboard: true
|
||||
)
|
||||
hostingViewController.view.backgroundColor = nil
|
||||
fpc.set(contentViewController: hostingViewController)
|
||||
fpc.addPanel(toParent: parentViewController, at: 1, animated: false)
|
||||
let contentViewController = UIViewController()
|
||||
contentViewController.view.addSubview(hostingViewController.view)
|
||||
fpc.set(contentViewController: contentViewController)
|
||||
fpc.addPanel(toParent: parentViewController, animated: false)
|
||||
|
||||
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
let bottomConstraint = hostingViewController.view.bottomAnchor.constraint(equalTo: contentViewController.view.bottomAnchor)
|
||||
bottomConstraint.priority = .defaultHigh
|
||||
NSLayoutConstraint.activate([
|
||||
hostingViewController.view.topAnchor.constraint(equalTo: contentViewController.view.topAnchor),
|
||||
hostingViewController.view.leadingAnchor.constraint(equalTo: contentViewController.view.leadingAnchor),
|
||||
hostingViewController.view.trailingAnchor.constraint(equalTo: contentViewController.view.trailingAnchor),
|
||||
bottomConstraint
|
||||
])
|
||||
}
|
||||
|
||||
func updateIfNeeded() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2021 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import FloatingPanel
|
||||
import UIKit
|
||||
|
||||
final class SearchPanelPhoneDelegate: FloatingPanelControllerDelegate {
|
||||
func floatingPanelWillBeginDragging(_ vc: FloatingPanelController) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
54B51134216C3D860033A6F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 54B51132216C3D860033A6F3 /* LaunchScreen.storyboard */; };
|
||||
54E26CB624A989090066C720 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E26CB524A989090066C720 /* Utils.swift */; };
|
||||
54E26CB824A98E310066C720 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E26CB724A98E310066C720 /* DetailViewController.swift */; };
|
||||
5D82A6A728D18422006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6A628D1841E006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -47,6 +48,7 @@
|
||||
54B51135216C3D860033A6F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
54E26CB524A989090066C720 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
|
||||
54E26CB724A98E310066C720 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
|
||||
5D82A6A628D1841E006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -55,6 +57,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
543844BD23D2BE2000D5EDE4 /* MapKit.framework in Frameworks */,
|
||||
5D82A6A728D18422006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
549D23D2233C77D5008EF4D7 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -65,6 +68,7 @@
|
||||
543844BB23D2BE1F00D5EDE4 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6A628D1841E006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
543844BC23D2BE2000D5EDE4 /* MapKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
@@ -336,6 +340,10 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Maps;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -355,6 +363,10 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Maps;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
||||
@@ -210,12 +210,10 @@ class SearchPanelPhoneDelegate: NSObject, FloatingPanelControllerDelegate, UIGes
|
||||
class SearchPanelLandscapeLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .tip
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
if #available(iOS 11.0, *) {
|
||||
return [
|
||||
@@ -244,11 +242,9 @@ class DetailPanelPhoneDelegate: NSObject, FloatingPanelControllerDelegate, UIGes
|
||||
|
||||
class DetailPanelPhoneLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
@@ -297,13 +293,11 @@ class SearchPanelPadDelegate: NSObject, FloatingPanelControllerDelegate, UIGestu
|
||||
class SearchPanelPadLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .top
|
||||
let initialState: FloatingPanelState = .tip
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 80.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 200.0, edge: .top, referenceGuide: .superview),
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 60.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 80.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 200.0, edge: .top, referenceGuide: .superview),
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 60.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
@@ -357,11 +351,9 @@ class DetailPanelPadDelegate: NSObject, FloatingPanelControllerDelegate, UIGestu
|
||||
|
||||
class DetailPanelPadLeftLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .left
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 375, edge: .left, referenceGuide: .superview)
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 375, edge: .left, referenceGuide: .superview)
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
@@ -370,11 +362,9 @@ class DetailPanelPadLeftLayout: FloatingPanelLayout {
|
||||
|
||||
class DetailPanelPadRightLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .right
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 375, edge: .right, referenceGuide: .superview)
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 375, edge: .right, referenceGuide: .superview)
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
|
||||
@@ -18,13 +18,12 @@
|
||||
5442E24A25FC53C100A26F43 /* DebugTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E24925FC53C100A26F43 /* DebugTextViewController.swift */; };
|
||||
5442E25225FC541700A26F43 /* NestedScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5442E25125FC541700A26F43 /* NestedScrollViewController.swift */; };
|
||||
54496C59263A7E5A0031E0C8 /* UseCaseController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54496C58263A7E5A0031E0C8 /* UseCaseController.swift */; };
|
||||
544BC56826CC918200D0A436 /* AdaptiveLayoutTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 544BC56726CC918200D0A436 /* AdaptiveLayoutTestViewController.swift */; };
|
||||
545DB9EE21511E6300CA77B8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9ED21511E6300CA77B8 /* AppDelegate.swift */; };
|
||||
545DB9F021511E6300CA77B8 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9EF21511E6300CA77B8 /* MainViewController.swift */; };
|
||||
545DB9F321511E6300CA77B8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F121511E6300CA77B8 /* Main.storyboard */; };
|
||||
545DB9F521511E6400CA77B8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F421511E6400CA77B8 /* Assets.xcassets */; };
|
||||
545DB9F821511E6400CA77B8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 545DB9F621511E6400CA77B8 /* LaunchScreen.storyboard */; };
|
||||
545DBA0321511E6400CA77B8 /* SampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DBA0221511E6400CA77B8 /* SampleTests.swift */; };
|
||||
545DBA0E21511E6400CA77B8 /* SampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DBA0D21511E6400CA77B8 /* SampleUITests.swift */; };
|
||||
546341A125C6415100CA0596 /* UseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 546341A025C6415100CA0596 /* UseCase.swift */; };
|
||||
546341AC25C6426500CA0596 /* CustomState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 546341AB25C6426500CA0596 /* CustomState.swift */; };
|
||||
549D23CB233C7779008EF4D7 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CA233C7779008EF4D7 /* FloatingPanel.framework */; };
|
||||
@@ -33,25 +32,9 @@
|
||||
54CDC5D8215BBE23007D205C /* SupplementaryViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */; };
|
||||
54EAD35B263A75EB006A36EA /* PanelLayouts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EAD35A263A75EB006A36EA /* PanelLayouts.swift */; };
|
||||
54EAD365263A765F006A36EA /* PagePanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EAD364263A765F006A36EA /* PagePanelController.swift */; };
|
||||
5D82A6AD28D1843C006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6AC28D18438006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
545DB9FF21511E6400CA77B8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 545DB9E221511E6300CA77B8 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 545DB9E921511E6300CA77B8;
|
||||
remoteInfo = FloatingModalSample;
|
||||
};
|
||||
545DBA0A21511E6400CA77B8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 545DB9E221511E6300CA77B8 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 545DB9E921511E6300CA77B8;
|
||||
remoteInfo = FloatingModalSample;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
549D23CD233C7779008EF4D7 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
@@ -78,6 +61,7 @@
|
||||
5442E24925FC53C100A26F43 /* DebugTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugTextViewController.swift; sourceTree = "<group>"; };
|
||||
5442E25125FC541700A26F43 /* NestedScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedScrollViewController.swift; sourceTree = "<group>"; };
|
||||
54496C58263A7E5A0031E0C8 /* UseCaseController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseCaseController.swift; sourceTree = "<group>"; };
|
||||
544BC56726CC918200D0A436 /* AdaptiveLayoutTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveLayoutTestViewController.swift; sourceTree = "<group>"; };
|
||||
545DB9EA21511E6300CA77B8 /* Samples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Samples.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DB9ED21511E6300CA77B8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
545DB9EF21511E6300CA77B8 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -85,12 +69,6 @@
|
||||
545DB9F421511E6400CA77B8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
545DB9F721511E6400CA77B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
545DB9F921511E6400CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DB9FE21511E6400CA77B8 /* SamplesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SamplesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DBA0221511E6400CA77B8 /* SampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleTests.swift; sourceTree = "<group>"; };
|
||||
545DBA0421511E6400CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DBA0921511E6400CA77B8 /* SamplesUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SamplesUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
545DBA0D21511E6400CA77B8 /* SampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleUITests.swift; sourceTree = "<group>"; };
|
||||
545DBA0F21511E6400CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
546341A025C6415100CA0596 /* UseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseCase.swift; sourceTree = "<group>"; };
|
||||
546341AB25C6426500CA0596 /* CustomState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomState.swift; sourceTree = "<group>"; };
|
||||
549D23CA233C7779008EF4D7 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -98,6 +76,7 @@
|
||||
54CDC5D7215BBE23007D205C /* SupplementaryViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupplementaryViews.swift; sourceTree = "<group>"; };
|
||||
54EAD35A263A75EB006A36EA /* PanelLayouts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanelLayouts.swift; sourceTree = "<group>"; };
|
||||
54EAD364263A765F006A36EA /* PagePanelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagePanelController.swift; sourceTree = "<group>"; };
|
||||
5D82A6AC28D18438006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -105,24 +84,11 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D82A6AD28D1843C006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
549D23CB233C7779008EF4D7 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9FB21511E6400CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DBA0621511E6400CA77B8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -139,6 +105,7 @@
|
||||
5442E22725FC51E200A26F43 /* MultiPanelController.swift */,
|
||||
5442E22B25FC521F00A26F43 /* SettingsViewController.swift */,
|
||||
5442E22F25FC525200A26F43 /* TabBarViewController.swift */,
|
||||
544BC56726CC918200D0A436 /* AdaptiveLayoutTestViewController.swift */,
|
||||
);
|
||||
path = ContentViewControllers;
|
||||
sourceTree = "<group>";
|
||||
@@ -148,9 +115,8 @@
|
||||
children = (
|
||||
549D23CA233C7779008EF4D7 /* FloatingPanel.framework */,
|
||||
545DB9EC21511E6300CA77B8 /* Sources */,
|
||||
545DBA0121511E6400CA77B8 /* Tests */,
|
||||
545DBA0C21511E6400CA77B8 /* UITests */,
|
||||
545DB9EB21511E6300CA77B8 /* Products */,
|
||||
5D82A6AB28D18438006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -158,8 +124,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DB9EA21511E6300CA77B8 /* Samples.app */,
|
||||
545DB9FE21511E6400CA77B8 /* SamplesTests.xctest */,
|
||||
545DBA0921511E6400CA77B8 /* SamplesUITests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -183,24 +147,6 @@
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DBA0121511E6400CA77B8 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DBA0221511E6400CA77B8 /* SampleTests.swift */,
|
||||
545DBA0421511E6400CA77B8 /* Info.plist */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545DBA0C21511E6400CA77B8 /* UITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
545DBA0D21511E6400CA77B8 /* SampleUITests.swift */,
|
||||
545DBA0F21511E6400CA77B8 /* Info.plist */,
|
||||
);
|
||||
path = UITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
546341AA25C6421000CA0596 /* UseCases */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -211,6 +157,14 @@
|
||||
path = UseCases;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6AB28D18438006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6AC28D18438006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -232,42 +186,6 @@
|
||||
productReference = 545DB9EA21511E6300CA77B8 /* Samples.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
545DB9FD21511E6400CA77B8 /* SamplesTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DBA1521511E6400CA77B8 /* Build configuration list for PBXNativeTarget "SamplesTests" */;
|
||||
buildPhases = (
|
||||
545DB9FA21511E6400CA77B8 /* Sources */,
|
||||
545DB9FB21511E6400CA77B8 /* Frameworks */,
|
||||
545DB9FC21511E6400CA77B8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
545DBA0021511E6400CA77B8 /* PBXTargetDependency */,
|
||||
);
|
||||
name = SamplesTests;
|
||||
productName = FloatingModalSampleTests;
|
||||
productReference = 545DB9FE21511E6400CA77B8 /* SamplesTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
545DBA0821511E6400CA77B8 /* SamplesUITests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 545DBA1821511E6400CA77B8 /* Build configuration list for PBXNativeTarget "SamplesUITests" */;
|
||||
buildPhases = (
|
||||
545DBA0521511E6400CA77B8 /* Sources */,
|
||||
545DBA0621511E6400CA77B8 /* Frameworks */,
|
||||
545DBA0721511E6400CA77B8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
545DBA0B21511E6400CA77B8 /* PBXTargetDependency */,
|
||||
);
|
||||
name = SamplesUITests;
|
||||
productName = FloatingModalSampleUITests;
|
||||
productReference = 545DBA0921511E6400CA77B8 /* SamplesUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -281,14 +199,6 @@
|
||||
545DB9E921511E6300CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
};
|
||||
545DB9FD21511E6400CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
TestTargetID = 545DB9E921511E6300CA77B8;
|
||||
};
|
||||
545DBA0821511E6400CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
TestTargetID = 545DB9E921511E6300CA77B8;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 545DB9E521511E6300CA77B8 /* Build configuration list for PBXProject "Samples" */;
|
||||
@@ -305,8 +215,6 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
545DB9E921511E6300CA77B8 /* Samples */,
|
||||
545DB9FD21511E6400CA77B8 /* SamplesTests */,
|
||||
545DBA0821511E6400CA77B8 /* SamplesUITests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -322,20 +230,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9FC21511E6400CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DBA0721511E6400CA77B8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -347,6 +241,7 @@
|
||||
54496C59263A7E5A0031E0C8 /* UseCaseController.swift in Sources */,
|
||||
54CDC5D8215BBE23007D205C /* SupplementaryViews.swift in Sources */,
|
||||
54B51116216AFE5F0033A6F3 /* Extensions.swift in Sources */,
|
||||
544BC56826CC918200D0A436 /* AdaptiveLayoutTestViewController.swift in Sources */,
|
||||
5442E24A25FC53C100A26F43 /* DebugTextViewController.swift in Sources */,
|
||||
546341AC25C6426500CA0596 /* CustomState.swift in Sources */,
|
||||
5442E23A25FC52CD00A26F43 /* ModalViewController.swift in Sources */,
|
||||
@@ -365,37 +260,8 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DB9FA21511E6400CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DBA0321511E6400CA77B8 /* SampleTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
545DBA0521511E6400CA77B8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545DBA0E21511E6400CA77B8 /* SampleUITests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
545DBA0021511E6400CA77B8 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 545DB9E921511E6300CA77B8 /* Samples */;
|
||||
targetProxy = 545DB9FF21511E6400CA77B8 /* PBXContainerItemProxy */;
|
||||
};
|
||||
545DBA0B21511E6400CA77B8 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 545DB9E921511E6300CA77B8 /* Samples */;
|
||||
targetProxy = 545DBA0A21511E6400CA77B8 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
545DB9F121511E6300CA77B8 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@@ -541,11 +407,15 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Samples;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -560,11 +430,15 @@
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Sources/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Samples;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -572,90 +446,6 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DBA1621511E6400CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalSampleTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Samples.app/Samples";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DBA1721511E6400CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
INFOPLIST_FILE = Tests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalSampleTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Samples.app/Samples";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
545DBA1921511E6400CA77B8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
INFOPLIST_FILE = UITests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalSampleUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_TARGET_NAME = FloatingModalSample;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
545DBA1A21511E6400CA77B8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = J3D7L9FHSS;
|
||||
INFOPLIST_FILE = UITests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalSampleUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_TARGET_NAME = FloatingModalSample;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@@ -677,24 +467,6 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DBA1521511E6400CA77B8 /* Build configuration list for PBXNativeTarget "SamplesTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DBA1621511E6400CA77B8 /* Debug */,
|
||||
545DBA1721511E6400CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
545DBA1821511E6400CA77B8 /* Build configuration list for PBXNativeTarget "SamplesUITests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
545DBA1921511E6400CA77B8 /* Debug */,
|
||||
545DBA1A21511E6400CA77B8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 545DB9E221511E6300CA77B8 /* Project object */;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="RoN-h0-uBD">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="RoN-h0-uBD">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
@@ -15,7 +15,7 @@
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="RootNavigationController" id="RoN-h0-uBD" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="hNW-5m-Omi">
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="96"/>
|
||||
<rect key="frame" x="0.0" y="48" width="414" height="96"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
@@ -31,22 +31,22 @@
|
||||
<objects>
|
||||
<viewController id="jF4-A0-Eq6" customClass="MainViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Smh-Bd-AAc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="7IS-PU-x0P">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="M0G-C8-hAO" style="IBUITableViewCellStyleDefault" id="ySY-oA-g81">
|
||||
<rect key="frame" x="0.0" y="28" width="600" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ySY-oA-g81" id="sXB-nH-2g2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="M0G-C8-hAO">
|
||||
<rect key="frame" x="16" y="0.0" width="568" height="43.5"/>
|
||||
<rect key="frame" x="20" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -87,7 +87,7 @@
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="SettingsViewController" id="C1X-9Z-TyQ" customClass="SettingsViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="af9-Zr-Ppc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="197.33000000000001"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="197.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="n93-ZL-fmC">
|
||||
@@ -125,7 +125,7 @@
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="js8-Qv-lUC">
|
||||
<rect key="frame" x="262" y="0.5" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="toggleLargeTitle:" destination="C1X-9Z-TyQ" eventType="valueChanged" id="FJS-Ty-mCY"/>
|
||||
<action selector="toggleLargeTitle:" destination="C1X-9Z-TyQ" eventType="valueChanged" id="CxM-wn-r09"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
@@ -142,7 +142,7 @@
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="s6b-j9-8Kw">
|
||||
<rect key="frame" x="262" y="0.5" width="51" height="31"/>
|
||||
<connections>
|
||||
<action selector="toggleTranslucent:" destination="C1X-9Z-TyQ" eventType="valueChanged" id="nL4-3L-9hh"/>
|
||||
<action selector="toggleTranslucent:" destination="C1X-9Z-TyQ" eventType="valueChanged" id="w7r-AV-RqX"/>
|
||||
</connections>
|
||||
</switch>
|
||||
</subviews>
|
||||
@@ -163,8 +163,8 @@
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="197.33000000000001"/>
|
||||
<connections>
|
||||
<outlet property="largeTitlesSwicth" destination="js8-Qv-lUC" id="FOm-6k-ffi"/>
|
||||
<outlet property="translucentSwicth" destination="s6b-j9-8Kw" id="jmf-WH-bzZ"/>
|
||||
<outlet property="largeTitlesSwitch" destination="js8-Qv-lUC" id="szl-pU-uRE"/>
|
||||
<outlet property="translucentSwitch" destination="s6b-j9-8Kw" id="8yK-Du-jkM"/>
|
||||
<outlet property="versionLabel" destination="WmC-Tq-NDN" id="Woh-kK-U0m"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
@@ -177,11 +177,11 @@
|
||||
<objects>
|
||||
<viewController id="RpE-lI-27a" customClass="TabBarContentViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="JER-jz-KSq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IvG-yp-yzI">
|
||||
<rect key="frame" x="20" y="0.0" width="39" height="30"/>
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="RpE-lI-27a" eventType="touchUpInside" id="hj3-Xv-6Gq"/>
|
||||
@@ -208,11 +208,11 @@
|
||||
<objects>
|
||||
<viewController id="pOk-Zm-vD9" customClass="TabBarContentViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="85d-ub-G8k">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NbG-e8-HdI">
|
||||
<rect key="frame" x="20" y="0.0" width="39" height="30"/>
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="pOk-Zm-vD9" eventType="touchUpInside" id="111-PD-Pop"/>
|
||||
@@ -239,11 +239,11 @@
|
||||
<objects>
|
||||
<viewController id="lto-Zc-Vtp" customClass="TabBarContentViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="ji9-Ez-N7i">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eFN-tN-4Ct">
|
||||
<rect key="frame" x="20" y="0.0" width="39" height="30"/>
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="YL4-GP-ZEZ"/>
|
||||
@@ -383,22 +383,22 @@
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ModalViewController" id="bYI-y3-Rzb" customClass="ModalViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="qwo-GK-p1U">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="720"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vut-mK-Y4t" customClass="SafeAreaView" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="758" width="375" height="0.0"/>
|
||||
<rect key="frame" x="0.0" y="720" width="375" height="0.0"/>
|
||||
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sbF-Az-7sy">
|
||||
<rect key="frame" x="20" y="0.0" width="39" height="30"/>
|
||||
<rect key="frame" x="20" y="48" width="39" height="30"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<connections>
|
||||
<action selector="closeWithSender:" destination="bYI-y3-Rzb" eventType="touchUpInside" id="MSC-ch-YJK"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="44" translatesAutoresizingMaskIntoConstraints="NO" id="9p4-06-y2T">
|
||||
<rect key="frame" x="134.5" y="88" width="106" height="326"/>
|
||||
<rect key="frame" x="134.5" y="136" width="106" height="326"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="i9x-x5-n1q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="80" height="30"/>
|
||||
@@ -602,7 +602,7 @@
|
||||
<color key="backgroundColor" red="0.0078431372550000003" green="0.72156862749999995" blue="0.45882352939999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="noi-1a-5bZ" customClass="CloseButton" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="319" y="0.0" width="44" height="44"/>
|
||||
<rect key="frame" x="319" y="48" width="44" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="0jg-5D-A1F"/>
|
||||
<constraint firstAttribute="width" constant="44" id="1Cq-PA-wgW"/>
|
||||
@@ -612,7 +612,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillProportionally" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="qux-uG-4o2">
|
||||
<rect key="frame" x="8" y="8" width="148" height="31"/>
|
||||
<rect key="frame" x="8" y="56" width="148" height="31"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="fitToBounds" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7lq-d3-PKi">
|
||||
<rect key="frame" x="0.0" y="5.5" width="91" height="20.5"/>
|
||||
@@ -660,19 +660,19 @@
|
||||
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstItem="noi-1a-5bZ" firstAttribute="top" secondItem="aOK-7l-cA6" secondAttribute="top" id="EQy-cr-F2Y"/>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="top" secondItem="g7l-kO-y7q" secondAttribute="top" id="A4b-Le-m4I"/>
|
||||
<constraint firstItem="noi-1a-5bZ" firstAttribute="top" secondItem="aOK-7l-cA6" secondAttribute="top" priority="750" id="EQy-cr-F2Y"/>
|
||||
<constraint firstItem="tP3-oJ-4EB" firstAttribute="centerX" secondItem="aOK-7l-cA6" secondAttribute="centerX" id="EsD-Vf-dNZ"/>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="top" secondItem="aOK-7l-cA6" secondAttribute="top" id="Fff-HL-4mo"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="bottom" secondItem="g7l-kO-y7q" secondAttribute="bottom" id="JOL-wC-w74"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="bottom" secondItem="g7l-kO-y7q" secondAttribute="bottom" priority="750" id="JOL-wC-w74"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="leading" secondItem="aOK-7l-cA6" secondAttribute="leading" id="RiJ-Hb-OOZ"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="trailing" secondItem="aOK-7l-cA6" secondAttribute="trailing" id="Sof-yL-mwK"/>
|
||||
<constraint firstItem="tP3-oJ-4EB" firstAttribute="top" secondItem="g7l-kO-y7q" secondAttribute="top" constant="88" id="Zhb-Ss-epe"/>
|
||||
<constraint firstItem="tP3-oJ-4EB" firstAttribute="top" secondItem="g7l-kO-y7q" secondAttribute="top" priority="750" constant="88" id="Zhb-Ss-epe"/>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="trailing" secondItem="aOK-7l-cA6" secondAttribute="trailing" id="kkp-Yo-FQW"/>
|
||||
<constraint firstItem="aOK-7l-cA6" firstAttribute="trailing" secondItem="noi-1a-5bZ" secondAttribute="trailing" constant="12" id="lv9-Nf-HNB"/>
|
||||
<constraint firstItem="qux-uG-4o2" firstAttribute="top" secondItem="aOK-7l-cA6" secondAttribute="top" constant="8" id="naa-cf-ZIc"/>
|
||||
<constraint firstItem="Kva-Z7-0qY" firstAttribute="leading" secondItem="aOK-7l-cA6" secondAttribute="leading" id="oVC-i1-TwS"/>
|
||||
<constraint firstItem="aOK-7l-cA6" firstAttribute="bottom" secondItem="Kva-Z7-0qY" secondAttribute="bottom" id="rW2-mF-5DR"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="top" relation="greaterThanOrEqual" secondItem="tP3-oJ-4EB" secondAttribute="bottom" constant="88" id="vKQ-h9-uKt"/>
|
||||
<constraint firstItem="aOK-7l-cA6" firstAttribute="bottom" secondItem="Kva-Z7-0qY" secondAttribute="bottom" priority="750" id="rW2-mF-5DR"/>
|
||||
<constraint firstItem="8yw-OC-Ubk" firstAttribute="top" relation="greaterThanOrEqual" secondItem="tP3-oJ-4EB" secondAttribute="bottom" priority="750" constant="88" id="vKQ-h9-uKt"/>
|
||||
<constraint firstItem="qux-uG-4o2" firstAttribute="leading" secondItem="g7l-kO-y7q" secondAttribute="leading" constant="8" id="zXb-R9-bMO"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
@@ -782,7 +782,57 @@ Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1" y="734"/>
|
||||
</scene>
|
||||
<!--Adaptive Layout Test View Controller-->
|
||||
<scene sceneID="rDI-lU-wEx">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="AdaptiveLayoutTestViewController" id="5nC-6E-bXf" customClass="AdaptiveLayoutTestViewController" customModule="Samples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="jXL-Ss-NCJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="W7W-ET-Wco" customClass="IntrinsicTableView" customModule="Samples" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" restorationIdentifier="Cell" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="Mqi-zK-WA7">
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Mqi-zK-WA7" id="X46-Fp-6Hr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="5nC-6E-bXf" id="RHg-aY-HNW"/>
|
||||
<outlet property="delegate" destination="5nC-6E-bXf" id="0YX-fh-bB8"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="ZfG-sd-dcQ"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="W7W-ET-Wco" firstAttribute="trailing" secondItem="ZfG-sd-dcQ" secondAttribute="trailing" id="3kP-rg-7c6"/>
|
||||
<constraint firstAttribute="bottom" secondItem="W7W-ET-Wco" secondAttribute="bottom" id="FdS-X9-D1D"/>
|
||||
<constraint firstItem="W7W-ET-Wco" firstAttribute="leading" secondItem="ZfG-sd-dcQ" secondAttribute="leading" id="HXa-oO-jag"/>
|
||||
<constraint firstItem="W7W-ET-Wco" firstAttribute="top" secondItem="jXL-Ss-NCJ" secondAttribute="top" id="gMX-Wq-7G8"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<size key="freeformSize" width="375" height="778"/>
|
||||
<connections>
|
||||
<outlet property="tableView" destination="W7W-ET-Wco" id="N54-Fv-2Jq"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="7hJ-XW-9az" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4005" y="734"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<designables>
|
||||
<designable name="noi-1a-5bZ">
|
||||
<size key="intrinsicContentSize" width="30" height="30"/>
|
||||
</designable>
|
||||
</designables>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="r1P-2i-NDe"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class AdaptiveLayoutTestViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
||||
class PanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
|
||||
private unowned var targetGuide: UILayoutGuide
|
||||
|
||||
init(targetGuide: UILayoutGuide) {
|
||||
self.targetGuide = targetGuide
|
||||
}
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelAdaptiveLayoutAnchor(
|
||||
absoluteOffset: 0.0,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview,
|
||||
contentBoundingGuide: .safeArea
|
||||
),
|
||||
.half: FloatingPanelAdaptiveLayoutAnchor(
|
||||
fractionalOffset: 0.5,
|
||||
contentLayout: targetGuide,
|
||||
referenceGuide: .superview,
|
||||
contentBoundingGuide: .safeArea
|
||||
),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet weak var tableView: IntrinsicTableView!
|
||||
private let cellID = "Cell"
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
1
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
50
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
|
||||
cell.textLabel?.text = "\(indexPath.row)"
|
||||
return cell
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let headerView = UIView()
|
||||
headerView.backgroundColor = .orange
|
||||
return headerView
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
44.0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
40
|
||||
}
|
||||
}
|
||||
|
||||
class IntrinsicTableView: UITableView {
|
||||
|
||||
override var contentSize:CGSize {
|
||||
didSet {
|
||||
invalidateIntrinsicContentSize()
|
||||
}
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
layoutIfNeeded()
|
||||
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class DebugTableViewController: InspectableViewController {
|
||||
stackView.axis = .vertical
|
||||
stackView.distribution = .fillEqually
|
||||
stackView.alignment = .trailing
|
||||
stackView.spacing = 10.0
|
||||
stackView.spacing = 4
|
||||
return stackView
|
||||
}()
|
||||
private lazy var reorderButton: UIButton = {
|
||||
@@ -28,40 +28,48 @@ class DebugTableViewController: InspectableViewController {
|
||||
button.addTarget(self, action: #selector(reorderItems), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
private lazy var trackingSwitchWrapper: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .horizontal
|
||||
stackView.distribution = .fillProportionally
|
||||
stackView.alignment = .center
|
||||
stackView.spacing = 8.0
|
||||
stackView.addArrangedSubview(trackingLabel)
|
||||
stackView.addArrangedSubview(trackingSwitch)
|
||||
return stackView
|
||||
private lazy var trackingButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setTitle(Menu.trackScrolling.rawValue, for: .normal)
|
||||
button.setTitleColor(view.tintColor, for: .normal)
|
||||
button.addTarget(self, action: #selector(toggleTrackingScroll), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
private lazy var trackingLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Tracking"
|
||||
label.font = UIFont.systemFont(ofSize: 17.0, weight: .regular)
|
||||
return label
|
||||
}()
|
||||
private lazy var trackingSwitch: UISwitch = {
|
||||
let trackingSwitch = UISwitch()
|
||||
trackingSwitch.isOn = true
|
||||
trackingSwitch.addTarget(self, action: #selector(turnTrackingOn), for: .touchUpInside)
|
||||
return trackingSwitch
|
||||
private lazy var followingButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setTitleColor(view.tintColor, for: .normal)
|
||||
button.addTarget(self, action: #selector(toggleFollowingScroll), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var kvoObservers: [NSKeyValueObservation] = []
|
||||
|
||||
private var fpc: FloatingPanelController? { parent as? FloatingPanelController }
|
||||
private lazy var items: [String] = {
|
||||
let items = (0..<100).map { "Items \($0)" }
|
||||
return Command.replace(items: items)
|
||||
}()
|
||||
private var itemHeight: CGFloat = 66.0
|
||||
|
||||
// MARK: Flags
|
||||
private var tracksScrollView: Bool = false {
|
||||
didSet {
|
||||
let title = "\(Menu.trackScrolling.rawValue): \(tracksScrollView ? "on" : "off")"
|
||||
trackingButton.setTitle(title, for: .normal)
|
||||
}
|
||||
}
|
||||
private var followsScrollViewBouncing: Bool = false {
|
||||
didSet {
|
||||
let title = "\(Menu.followScrolling.rawValue): \(followsScrollViewBouncing ? "on" : "off")"
|
||||
followingButton.setTitle(title, for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
enum Menu: String, CaseIterable {
|
||||
case turnOffTracking = "Tracking"
|
||||
case trackScrolling = "Tracking"
|
||||
case followScrolling = "Following"
|
||||
case reorder = "Reorder"
|
||||
}
|
||||
|
||||
@@ -136,13 +144,19 @@ class DebugTableViewController: InspectableViewController {
|
||||
switch menu {
|
||||
case .reorder:
|
||||
buttonStackView.addArrangedSubview(reorderButton)
|
||||
case .turnOffTracking:
|
||||
buttonStackView.addArrangedSubview(trackingSwitchWrapper)
|
||||
case .trackScrolling:
|
||||
buttonStackView.addArrangedSubview(trackingButton)
|
||||
case .followScrolling:
|
||||
buttonStackView.addArrangedSubview(followingButton)
|
||||
}
|
||||
}
|
||||
// Set titles
|
||||
tracksScrollView = true
|
||||
followsScrollViewBouncing = false
|
||||
}
|
||||
|
||||
// MARK: - Menu
|
||||
|
||||
@objc
|
||||
private func reorderItems() {
|
||||
if reorderButton.titleLabel?.text == Menu.reorder.rawValue {
|
||||
@@ -155,15 +169,21 @@ class DebugTableViewController: InspectableViewController {
|
||||
}
|
||||
|
||||
@objc
|
||||
private func turnTrackingOn(_ sender: UISwitch) {
|
||||
guard let fpc = self.parent as? FloatingPanelController else { return }
|
||||
if sender.isOn {
|
||||
private func toggleTrackingScroll() {
|
||||
tracksScrollView.toggle()
|
||||
guard let fpc = fpc else { return }
|
||||
if tracksScrollView {
|
||||
fpc.track(scrollView: tableView)
|
||||
} else {
|
||||
fpc.untrack(scrollView: tableView)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func toggleFollowingScroll() {
|
||||
followsScrollViewBouncing.toggle()
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
private func execute(command: Command, sourceView: UIView) {
|
||||
@@ -250,6 +270,9 @@ extension DebugTableViewController: UITableViewDataSource {
|
||||
|
||||
extension DebugTableViewController: UITableViewDelegate {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
if followsScrollViewBouncing {
|
||||
fpc?.followScrollViewBouncing()
|
||||
}
|
||||
print("TableView --- ", scrollView.contentOffset, scrollView.contentInset)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,14 +65,12 @@ final class ModalViewController: UIViewController, FloatingPanelControllerDelega
|
||||
}
|
||||
|
||||
class ModalSecondLayout: FloatingPanelLayout {
|
||||
var position: FloatingPanelPosition = .bottom
|
||||
var initialState: FloatingPanelState { .half }
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .half
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,9 @@ final class MultiPanelController: FloatingPanelController, FloatingPanelControll
|
||||
private final class FirstViewLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 40.0, edge: .top, referenceGuide: .superview)
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 40.0, edge: .top, referenceGuide: .superview)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import UIKit
|
||||
import FloatingPanel
|
||||
|
||||
final class SettingsViewController: InspectableViewController {
|
||||
@IBOutlet weak var largeTitlesSwicth: UISwitch!
|
||||
@IBOutlet weak var translucentSwicth: UISwitch!
|
||||
@IBOutlet weak var largeTitlesSwitch: UISwitch!
|
||||
@IBOutlet weak var translucentSwitch: UISwitch!
|
||||
@IBOutlet weak var versionLabel: UILabel!
|
||||
|
||||
override func viewDidLoad() {
|
||||
@@ -16,12 +16,12 @@ final class SettingsViewController: InspectableViewController {
|
||||
super.viewDidLayoutSubviews()
|
||||
if #available(iOS 11.0, *) {
|
||||
let prefersLargeTitles = navigationController!.navigationBar.prefersLargeTitles
|
||||
largeTitlesSwicth.setOn(prefersLargeTitles, animated: false)
|
||||
largeTitlesSwitch.setOn(prefersLargeTitles, animated: false)
|
||||
} else {
|
||||
largeTitlesSwicth.isEnabled = false
|
||||
largeTitlesSwitch.isEnabled = false
|
||||
}
|
||||
let isTranslucent = navigationController!.navigationBar.isTranslucent
|
||||
translucentSwicth.setOn(isTranslucent, animated: false)
|
||||
translucentSwitch.setOn(isTranslucent, animated: false)
|
||||
}
|
||||
|
||||
@IBAction func toggleLargeTitle(_ sender: UISwitch) {
|
||||
@@ -30,7 +30,19 @@ final class SettingsViewController: InspectableViewController {
|
||||
}
|
||||
}
|
||||
@IBAction func toggleTranslucent(_ sender: UISwitch) {
|
||||
navigationController?.navigationBar.isTranslucent = sender.isOn
|
||||
// White non-translucent navigation bar, supports dark appearance
|
||||
if #available(iOS 15, *) {
|
||||
let appearance = UINavigationBarAppearance()
|
||||
if sender.isOn {
|
||||
appearance.configureWithTransparentBackground()
|
||||
} else {
|
||||
appearance.configureWithOpaqueBackground()
|
||||
}
|
||||
navigationController?.navigationBar.standardAppearance = appearance
|
||||
navigationController?.navigationBar.scrollEdgeAppearance = appearance
|
||||
} else {
|
||||
navigationController?.navigationBar.isTranslucent = sender.isOn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -195,14 +195,12 @@ class OneTabBarPanelLayout: FloatingPanelLayout {
|
||||
}
|
||||
|
||||
class TwoTabBarPanelLayout: FloatingPanelLayout {
|
||||
var initialState: FloatingPanelState { .half }
|
||||
var position: FloatingPanelPosition { .bottom }
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 100.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 261.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
let initialState: FloatingPanelState = .half
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 100.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 261.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
|
||||
class TwoTabBarPanelBehavior: FloatingPanelBehavior {
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
func makeBoundsLayoutGuide() -> UILayoutGuide {
|
||||
let guide = UILayoutGuide()
|
||||
addLayoutGuide(guide)
|
||||
NSLayoutConstraint.activate([
|
||||
guide.topAnchor.constraint(equalTo: topAnchor),
|
||||
guide.leftAnchor.constraint(equalTo: leftAnchor),
|
||||
guide.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
guide.rightAnchor.constraint(equalTo: rightAnchor),
|
||||
])
|
||||
return guide
|
||||
}
|
||||
}
|
||||
|
||||
protocol LayoutGuideProvider {
|
||||
var topAnchor: NSLayoutYAxisAnchor { get }
|
||||
var bottomAnchor: NSLayoutYAxisAnchor { get }
|
||||
|
||||
@@ -23,14 +23,11 @@ extension MainViewController: FloatingPanelLayout {
|
||||
class TopPositionedPanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .top
|
||||
let initialState: FloatingPanelState = .full
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 88.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 216.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .top, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 88.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 216.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .top, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
|
||||
class IntrinsicPanelLayout: FloatingPanelBottomLayout {
|
||||
@@ -45,13 +42,10 @@ class IntrinsicPanelLayout: FloatingPanelBottomLayout {
|
||||
class RemovablePanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .half
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 130.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
@@ -61,13 +55,10 @@ class RemovablePanelLayout: FloatingPanelLayout {
|
||||
class RemovablePanelLandscapeLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 216.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 216.0, edge: .bottom, referenceGuide: .safeArea)
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
@@ -77,12 +68,9 @@ class RemovablePanelLandscapeLayout: FloatingPanelLayout {
|
||||
class ModalPanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(absoluteOffset: 0.0, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(absoluteOffset: 0.0, referenceGuide: .safeArea),
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.3
|
||||
|
||||
@@ -10,6 +10,7 @@ enum UseCase: Int, CaseIterable {
|
||||
case showPanelModal
|
||||
case showMultiPanelModal
|
||||
case showPanelInSheetModal
|
||||
case showOnWindow
|
||||
case showTabBar
|
||||
case showPageView
|
||||
case showPageContentView
|
||||
@@ -34,6 +35,7 @@ extension UseCase {
|
||||
case .showModal: return "Show Modal"
|
||||
case .showPanelModal: return "Show Panel Modal"
|
||||
case .showMultiPanelModal: return "Show Multi Panel Modal"
|
||||
case .showOnWindow: return "Show Panel over Window"
|
||||
case .showPanelInSheetModal: return "Show Panel in Sheet Modal"
|
||||
case .showTabBar: return "Show Tab Bar"
|
||||
case .showPageView: return "Show Page View"
|
||||
@@ -50,7 +52,9 @@ extension UseCase {
|
||||
case .showCustomStatePanel: return "Show Panel with Custom state"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UseCase {
|
||||
private enum Content {
|
||||
case storyboard(String)
|
||||
case viewController(UIViewController)
|
||||
@@ -63,6 +67,7 @@ extension UseCase {
|
||||
case .showDetail: return .storyboard(String(describing: DetailViewController.self))
|
||||
case .showModal: return .storyboard(String(describing: ModalViewController.self))
|
||||
case .showMultiPanelModal: return .viewController(DebugTableViewController())
|
||||
case .showOnWindow: return .viewController(DebugTableViewController())
|
||||
case .showPanelInSheetModal: return .viewController(DebugTableViewController())
|
||||
case .showPanelModal: return .viewController(DebugTableViewController())
|
||||
case .showTabBar: return .storyboard(String(describing: TabBarViewController.self))
|
||||
@@ -76,7 +81,7 @@ extension UseCase {
|
||||
case .showNavigationController: return .storyboard("RootNavigationController") // Storyboard only
|
||||
case .showTopPositionedPanel: return .viewController(DebugTableViewController())
|
||||
case .showAdaptivePanel: return .storyboard(String(describing: ImageViewController.self))
|
||||
case .showAdaptivePanelWithCustomGuide: return .storyboard(String(describing: ImageViewController.self))
|
||||
case .showAdaptivePanelWithCustomGuide: return .storyboard(String(describing: AdaptiveLayoutTestViewController.self))
|
||||
case .showCustomStatePanel: return .viewController(DebugTableViewController())
|
||||
}
|
||||
}
|
||||
@@ -86,6 +91,7 @@ extension UseCase {
|
||||
case .storyboard(let id):
|
||||
return storyboard.instantiateViewController(withIdentifier: id)
|
||||
case .viewController(let vc):
|
||||
vc.loadViewIfNeeded()
|
||||
return vc
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ final class UseCaseController: NSObject {
|
||||
private var detailPanelVC: FloatingPanelController!
|
||||
private var settingsPanelVC: FloatingPanelController!
|
||||
private lazy var pagePanelController = PagePanelController()
|
||||
private lazy var overWindowPanelVC = FloatingPanelController()
|
||||
|
||||
init(mainVC: MainViewController) {
|
||||
self.mainVC = mainVC
|
||||
@@ -157,6 +158,19 @@ extension UseCaseController {
|
||||
let fpc = MultiPanelController()
|
||||
mainVC.present(fpc, animated: true, completion: nil)
|
||||
|
||||
case .showOnWindow:
|
||||
let fpc = overWindowPanelVC
|
||||
fpc.backdropView.dismissalTapGestureRecognizer.isEnabled = true
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
|
||||
guard let window = UIApplication.shared.windows.first else { fatalError("Any window not found") }
|
||||
|
||||
window.addSubview(fpc.view)
|
||||
fpc.view.frame = window.bounds
|
||||
fpc.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
fpc.show(animated: true)
|
||||
case .showPanelInSheetModal:
|
||||
let fpc = FloatingPanelController()
|
||||
let contentVC = UIViewController()
|
||||
@@ -212,28 +226,40 @@ extension UseCaseController {
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showTopPositionedPanel: // For debug
|
||||
let fpc = FloatingPanelController()
|
||||
let fpc = FloatingPanelController(delegate: self)
|
||||
let contentVC = UIViewController()
|
||||
contentVC.view.backgroundColor = .red
|
||||
fpc.set(contentViewController: contentVC)
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showAdaptivePanel, .showAdaptivePanelWithCustomGuide:
|
||||
case .showAdaptivePanel:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
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)
|
||||
|
||||
case .showAdaptivePanelWithCustomGuide:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.isRemovalInteractionEnabled = true
|
||||
fpc.contentInsetAdjustmentBehavior = .always
|
||||
fpc.surfaceView.appearance = {
|
||||
let appearance = SurfaceAppearance()
|
||||
appearance.cornerRadius = 6.0
|
||||
return appearance
|
||||
}()
|
||||
|
||||
|
||||
fpc.set(contentViewController: contentVC)
|
||||
fpc.ext_trackScrollView(in: contentVC)
|
||||
fpc.layout = AdaptiveLayoutTestViewController.PanelLayout(targetGuide: contentVC.view.makeBoundsLayoutGuide())
|
||||
addMain(panel: fpc)
|
||||
|
||||
case .showCustomStatePanel:
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.delegate = self
|
||||
@@ -283,7 +309,7 @@ extension UseCaseController {
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
@objc
|
||||
private func handleSurface(tapGesture: UITapGestureRecognizer) {
|
||||
switch mainPanelVC.state {
|
||||
case .full:
|
||||
@@ -377,6 +403,9 @@ private extension FloatingPanelController {
|
||||
case let contentVC as ImageViewController:
|
||||
track(scrollView: contentVC.scrollView)
|
||||
|
||||
case let contentVC as AdaptiveLayoutTestViewController:
|
||||
track(scrollView: contentVC.tableView)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import XCTest
|
||||
@testable import FloatingPanelSample
|
||||
|
||||
class SampleTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import XCTest
|
||||
|
||||
class SampleUITests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
|
||||
XCUIApplication().launch()
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// Use recording to get started writing UI tests.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
545BA71421BA3217007F7846 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 545BA71321BA3217007F7846 /* main.m */; };
|
||||
545BA72621BA3BAF007F7846 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 545BA72521BA3BAF007F7846 /* FloatingPanel.framework */; };
|
||||
545BA72721BA3BAF007F7846 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 545BA72521BA3BAF007F7846 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
5D82A6B028D18447006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6AF28D18443006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -44,6 +45,7 @@
|
||||
545BA71321BA3217007F7846 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
545BA72221BA3867007F7846 /* SamplesObjC-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SamplesObjC-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
545BA72521BA3BAF007F7846 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5D82A6AF28D18443006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -51,6 +53,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D82A6B028D18447006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
545BA72621BA3BAF007F7846 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -64,6 +67,7 @@
|
||||
545BA72521BA3BAF007F7846 /* FloatingPanel.framework */,
|
||||
545BA70321BA3214007F7846 /* SamplesObjC */,
|
||||
545BA70221BA3214007F7846 /* Products */,
|
||||
5D82A6AE28D18443006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -92,6 +96,14 @@
|
||||
path = SamplesObjC;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6AE28D18443006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6AF28D18443006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -320,6 +332,10 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.SamplesObjC;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "SamplesObjC/SamplesObjC-Bridging-Header.h";
|
||||
@@ -342,6 +358,10 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.SamplesObjC;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "SamplesObjC/SamplesObjC-Bridging-Header.h";
|
||||
|
||||
@@ -29,7 +29,6 @@ static FloatingPanelState *_lastQuart;
|
||||
|
||||
FloatingPanelController *fpc = [[FloatingPanelController alloc] init];
|
||||
[fpc setContentViewController:nil];
|
||||
[fpc trackScrollView:nil];
|
||||
[fpc setDelegate:self];
|
||||
|
||||
[fpc setLayout: [MyFloatingPanelLayout new]];
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
548DF95E21705BE10041922A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 548DF95C21705BE10041922A /* LaunchScreen.storyboard */; };
|
||||
549D23CF233C77CF008EF4D7 /* FloatingPanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */; };
|
||||
549D23D0233C77CF008EF4D7 /* FloatingPanel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
5D82A6AA28D18432006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6A928D1842B006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -39,6 +40,7 @@
|
||||
548DF95D21705BE10041922A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
548DF95F21705BE10041922A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FloatingPanel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5D82A6A928D1842B006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -46,6 +48,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D82A6AA28D18432006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
549D23CF233C77CF008EF4D7 /* FloatingPanel.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -59,6 +62,7 @@
|
||||
549D23CE233C77CF008EF4D7 /* FloatingPanel.framework */,
|
||||
548DF95221705BE00041922A /* Stocks */,
|
||||
548DF95121705BE00041922A /* Products */,
|
||||
5D82A6A828D1842A006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -83,6 +87,14 @@
|
||||
path = Stocks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5D82A6A828D1842A006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D82A6A928D1842B006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -312,6 +324,10 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Stocks;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -331,6 +347,10 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = example.Stocks;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
||||
@@ -101,14 +101,12 @@ class FloatingPanelStocksLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .tip
|
||||
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 56.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
/* Visible + ToolView */
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 85.0 + 44.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 56.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 262.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
/* Visible + ToolView */
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 85.0 + 44.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "FloatingPanel"
|
||||
s.version = "2.5.1"
|
||||
s.version = "2.6.3"
|
||||
s.summary = "FloatingPanel is a clean and easy-to-use UI component of a floating panel interface."
|
||||
s.description = <<-DESC
|
||||
FloatingPanel is a clean and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app.
|
||||
@@ -14,7 +14,7 @@ The new interface displays the related contents and utilities in parallel as a u
|
||||
s.platform = :ios, "10.0"
|
||||
s.source = { :git => "https://github.com/SCENEE/FloatingPanel.git", :tag => s.version.to_s }
|
||||
s.source_files = "Sources/*.swift"
|
||||
s.swift_versions = ['5.1', '5.2', '5.3']
|
||||
s.swift_version = '5.0'
|
||||
|
||||
s.framework = "UIKit"
|
||||
|
||||
|
||||
@@ -17,12 +17,10 @@
|
||||
545DB9E021511AC100CA77B8 /* Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DB9DF21511AC100CA77B8 /* Controller.swift */; };
|
||||
545DBA2B2152383100CA77B8 /* GrabberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DBA2A2152383100CA77B8 /* GrabberView.swift */; };
|
||||
546055BF2333C4740069F400 /* TestSupports.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542753C722C49A8F00D17955 /* TestSupports.swift */; };
|
||||
5469F4A224B003EF00537F8A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5469F49F24B003EF00537F8A /* LaunchScreen.storyboard */; };
|
||||
5469F4A324B003EF00537F8A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4A024B003EF00537F8A /* AppDelegate.swift */; };
|
||||
5469F4AE24B30D7E00537F8A /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4AD24B30D7E00537F8A /* State.swift */; };
|
||||
5469F4B024B30E1500537F8A /* LayoutAnchoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4AF24B30E1500537F8A /* LayoutAnchoring.swift */; };
|
||||
5469F4B224B30F1100537F8A /* Position.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4B124B30F1100537F8A /* Position.swift */; };
|
||||
5469F4B424B30F3500537F8A /* LayoutReferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4B324B30F3500537F8A /* LayoutReferences.swift */; };
|
||||
5469F4B424B30F3500537F8A /* LayoutProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469F4B324B30F3500537F8A /* LayoutProperties.swift */; };
|
||||
549C371F2361E15E007D8058 /* ExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549C371E2361E15D007D8058 /* ExtensionTests.swift */; };
|
||||
549E944522CF295D0050AECF /* StateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E944422CF295D0050AECF /* StateTests.swift */; };
|
||||
54A6B6B122968B530077F348 /* CoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A6B6B022968B530077F348 /* CoreTests.swift */; };
|
||||
@@ -34,6 +32,7 @@
|
||||
54CFBFC5215CD09C006B5735 /* Core.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CFBFC4215CD09C006B5735 /* Core.swift */; };
|
||||
54DBA3DC262E938500D75969 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54DBA3DB262E938500D75969 /* Extensions.swift */; };
|
||||
54E3992727141F5100A8F9ED /* FloatingPanel.docc in Sources */ = {isa = PBXBuildFile; fileRef = 54E3992627141F5100A8F9ED /* FloatingPanel.docc */; };
|
||||
5D82A6B528D18464006A44BA /* libswiftCoreGraphics.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D82A6B428D18461006A44BA /* libswiftCoreGraphics.tbd */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -44,13 +43,6 @@
|
||||
remoteGlobalIDString = 545DB9C02151169500CA77B8;
|
||||
remoteInfo = FloatingModalController;
|
||||
};
|
||||
54E740DC218AFE9F005C1A34 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 545DB9B82151169500CA77B8 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 54E740C9218AFD67005C1A34;
|
||||
remoteInfo = TestingHost;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -67,13 +59,10 @@
|
||||
545DB9D12151169500CA77B8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
545DB9DF21511AC100CA77B8 /* Controller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = "<group>"; };
|
||||
545DBA2A2152383100CA77B8 /* GrabberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrabberView.swift; sourceTree = "<group>"; };
|
||||
5469F49F24B003EF00537F8A /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
5469F4A024B003EF00537F8A /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
5469F4A124B003EF00537F8A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5469F4AD24B30D7E00537F8A /* State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = "<group>"; };
|
||||
5469F4AF24B30E1500537F8A /* LayoutAnchoring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutAnchoring.swift; sourceTree = "<group>"; };
|
||||
5469F4B124B30F1100537F8A /* Position.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Position.swift; sourceTree = "<group>"; };
|
||||
5469F4B324B30F3500537F8A /* LayoutReferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutReferences.swift; sourceTree = "<group>"; };
|
||||
5469F4B324B30F3500537F8A /* LayoutProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutProperties.swift; sourceTree = "<group>"; };
|
||||
549C371E2361E15D007D8058 /* ExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionTests.swift; sourceTree = "<group>"; };
|
||||
549E944422CF295D0050AECF /* StateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateTests.swift; sourceTree = "<group>"; };
|
||||
54A6B6B022968B530077F348 /* CoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreTests.swift; sourceTree = "<group>"; };
|
||||
@@ -85,7 +74,7 @@
|
||||
54CFBFC4215CD09C006B5735 /* Core.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core.swift; sourceTree = "<group>"; };
|
||||
54DBA3DB262E938500D75969 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
|
||||
54E3992627141F5100A8F9ED /* FloatingPanel.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = FloatingPanel.docc; sourceTree = "<group>"; };
|
||||
54E740CA218AFD67005C1A34 /* FloatingPanelTesting.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FloatingPanelTesting.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5D82A6B428D18461006A44BA /* libswiftCoreGraphics.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreGraphics.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/lib/swift/libswiftCoreGraphics.tbd; sourceTree = DEVELOPER_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -93,6 +82,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5D82A6B528D18464006A44BA /* libswiftCoreGraphics.tbd in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -104,13 +94,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
54E740C7218AFD67005C1A34 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -120,6 +103,7 @@
|
||||
545DB9C32151169500CA77B8 /* Sources */,
|
||||
545DB9CE2151169500CA77B8 /* Tests */,
|
||||
545DB9C22151169500CA77B8 /* Products */,
|
||||
5D82A6B328D18460006A44BA /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -128,7 +112,6 @@
|
||||
children = (
|
||||
545DB9C12151169500CA77B8 /* FloatingPanel.framework */,
|
||||
545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */,
|
||||
54E740CA218AFD67005C1A34 /* FloatingPanelTesting.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -141,7 +124,7 @@
|
||||
5469F4B124B30F1100537F8A /* Position.swift */,
|
||||
54CFBFC4215CD09C006B5735 /* Core.swift */,
|
||||
54CFBFC2215CD045006B5735 /* Layout.swift */,
|
||||
5469F4B324B30F3500537F8A /* LayoutReferences.swift */,
|
||||
5469F4B324B30F3500537F8A /* LayoutProperties.swift */,
|
||||
5469F4AF24B30E1500537F8A /* LayoutAnchoring.swift */,
|
||||
5450EEE321646DF500135936 /* Behavior.swift */,
|
||||
54352E9721A521CA00CBCA08 /* PassthroughView.swift */,
|
||||
@@ -161,7 +144,6 @@
|
||||
545DB9CE2151169500CA77B8 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5469F49E24B003EF00537F8A /* TestingApp */,
|
||||
54A6B6B022968B530077F348 /* CoreTests.swift */,
|
||||
545DB9CF2151169500CA77B8 /* ControllerTests.swift */,
|
||||
542753C522C49A6E00D17955 /* LayoutTests.swift */,
|
||||
@@ -174,14 +156,12 @@
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5469F49E24B003EF00537F8A /* TestingApp */ = {
|
||||
5D82A6B328D18460006A44BA /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5469F49F24B003EF00537F8A /* LaunchScreen.storyboard */,
|
||||
5469F4A024B003EF00537F8A /* AppDelegate.swift */,
|
||||
5469F4A124B003EF00537F8A /* Info.plist */,
|
||||
5D82A6B428D18461006A44BA /* libswiftCoreGraphics.tbd */,
|
||||
);
|
||||
path = TestingApp;
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
@@ -228,30 +208,12 @@
|
||||
);
|
||||
dependencies = (
|
||||
545DB9CD2151169500CA77B8 /* PBXTargetDependency */,
|
||||
54E740DD218AFE9F005C1A34 /* PBXTargetDependency */,
|
||||
);
|
||||
name = FloatingPanelTests;
|
||||
productName = FloatingModalControllerTests;
|
||||
productReference = 545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
54E740C9218AFD67005C1A34 /* TestingApp */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 54E740D9218AFD6A005C1A34 /* Build configuration list for PBXNativeTarget "TestingApp" */;
|
||||
buildPhases = (
|
||||
54E740C6218AFD67005C1A34 /* Sources */,
|
||||
54E740C7218AFD67005C1A34 /* Frameworks */,
|
||||
54E740C8218AFD67005C1A34 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = TestingApp;
|
||||
productName = TestingHost;
|
||||
productReference = 54E740CA218AFD67005C1A34 /* FloatingPanelTesting.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -268,10 +230,6 @@
|
||||
};
|
||||
545DB9C92151169500CA77B8 = {
|
||||
CreatedOnToolsVersion = 10.0;
|
||||
TestTargetID = 54E740C9218AFD67005C1A34;
|
||||
};
|
||||
54E740C9218AFD67005C1A34 = {
|
||||
CreatedOnToolsVersion = 10.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -290,7 +248,6 @@
|
||||
targets = (
|
||||
545DB9C02151169500CA77B8 /* FloatingPanel */,
|
||||
545DB9C92151169500CA77B8 /* FloatingPanelTests */,
|
||||
54E740C9218AFD67005C1A34 /* TestingApp */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -310,14 +267,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
54E740C8218AFD67005C1A34 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5469F4A224B003EF00537F8A /* LaunchScreen.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -329,7 +278,7 @@
|
||||
5469F4B024B30E1500537F8A /* LayoutAnchoring.swift in Sources */,
|
||||
54CDC5D3215B6D5A007D205C /* SurfaceView.swift in Sources */,
|
||||
54CFBFC3215CD045006B5735 /* Layout.swift in Sources */,
|
||||
5469F4B424B30F3500537F8A /* LayoutReferences.swift in Sources */,
|
||||
5469F4B424B30F3500537F8A /* LayoutProperties.swift in Sources */,
|
||||
54CDC5D5215B6D8D007D205C /* BackdropView.swift in Sources */,
|
||||
54352E9821A521CA00CBCA08 /* PassthroughView.swift in Sources */,
|
||||
54CFBFC5215CD09C006B5735 /* Core.swift in Sources */,
|
||||
@@ -358,14 +307,6 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
54E740C6218AFD67005C1A34 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5469F4A324B003EF00537F8A /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
@@ -374,11 +315,6 @@
|
||||
target = 545DB9C02151169500CA77B8 /* FloatingPanel */;
|
||||
targetProxy = 545DB9CC2151169500CA77B8 /* PBXContainerItemProxy */;
|
||||
};
|
||||
54E740DD218AFE9F005C1A34 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 54E740C9218AFD67005C1A34 /* TestingApp */;
|
||||
targetProxy = 54E740DC218AFE9F005C1A34 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
@@ -581,11 +517,10 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalControllerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FloatingPanelTesting.app/FloatingPanelTesting";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -602,47 +537,10 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalControllerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FloatingPanelTesting.app/FloatingPanelTesting";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
54E740DA218AFD6A005C1A34 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Tests/TestingApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTesting;
|
||||
PRODUCT_NAME = FloatingPanelTesting;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
54E740DB218AFD6A005C1A34 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Tests/TestingApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTesting;
|
||||
PRODUCT_NAME = FloatingPanelTesting;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -755,25 +653,10 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingModalControllerTests;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FloatingPanelTesting.app/FloatingPanelTesting";
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
54E8AC6A2286CFB6000C5A12 /* Test */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = Tests/TestingApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.scenee.FloatingPanelTesting;
|
||||
PRODUCT_NAME = FloatingPanelTesting;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
@@ -810,16 +693,6 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
54E740D9218AFD6A005C1A34 /* Build configuration list for PBXNativeTarget "TestingApp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
54E740DA218AFD6A005C1A34 /* Debug */,
|
||||
54E740DB218AFD6A005C1A34 /* Release */,
|
||||
54E8AC6A2286CFB6000C5A12 /* Test */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 545DB9B82151169500CA77B8 /* Project object */;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[](https://travis-ci.org/SCENEE/FloatingPanel)
|
||||
[](https://cocoapods.org/pods/FloatingPanel)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://swift.org/)
|
||||
[](https://cocoapods.org/pods/FloatingPanel)
|
||||
[](https://swift.org/)
|
||||
[](https://cocoapods.org/pods/FloatingPanel)
|
||||

|
||||
[](https://github.com/Carthage/Carthage)
|
||||
|
||||
# FloatingPanel
|
||||
|
||||
FloatingPanel is a simple and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app.
|
||||
The new interface displays the related contents and utilities in parallel as a user wants.
|
||||
FloatingPanel is a simple and easy-to-use UI component designed for a user interface featured in Apple Maps, Shortcuts and Stocks app.
|
||||
The user interface displays related content and utilities alongside the main content.
|
||||
|
||||
📝[Here](https://docs.scenee.com/documentation/floatingpanel) is the API references for the latest version powered by [DocC](https://developer.apple.com/documentation/docc).
|
||||
Please see also [the API reference](https://floatingpanel.github.io/2.6.3/documentation/floatingpanel/) for more details.
|
||||
|
||||

|
||||

|
||||
@@ -75,14 +75,14 @@ The new interface displays the related contents and utilities in parallel as a u
|
||||
- [x] Removal interaction
|
||||
- [x] Multi panel support
|
||||
- [x] Modal presentation
|
||||
- [x] 4 positioning support(top, left, bottom, right)
|
||||
- [x] Support for 4 positions (top, left, bottom, right)
|
||||
- [x] 1 or more magnetic anchors(full, half, tip and more)
|
||||
- [x] Layout support for all trait environments(i.e. Landscape orientation)
|
||||
- [x] Common UI elements: surface, backdrop and grabber handle
|
||||
- [x] Free from common issues of Auto Layout and gesture handling
|
||||
- [x] Free from common Auto Layout and gesture handling issues
|
||||
- [x] Compatible with Objective-C
|
||||
|
||||
Examples are here.
|
||||
Examples can be found here:
|
||||
|
||||
- [Examples/Maps](https://github.com/SCENEE/FloatingPanel/tree/master/Examples/Maps) like Apple Maps.app.
|
||||
- [Examples/Stocks](https://github.com/SCENEE/FloatingPanel/tree/master/Examples/Stocks) like Apple Stocks.app.
|
||||
@@ -91,11 +91,11 @@ Examples are here.
|
||||
|
||||
## Requirements
|
||||
|
||||
FloatingPanel is written in Swift 5.0+. Compatible with iOS 11.0+.
|
||||
FloatingPanel is written in Swift 5.0+ and compatible with iOS 11.0+.
|
||||
|
||||
The deployment is still iOS 10, but it is recommended to use this library on iOS 11+.
|
||||
While it still supports iOS 10, it is recommended to use this library on iOS 11+.
|
||||
|
||||
:pencil2: You would like to use Swift 4.0. Please use FloatingPanel v1.
|
||||
:pencil2: If you'd like to use Swift 4.0, please use FloatingPanel v1.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -269,13 +269,11 @@ class ViewController: UIViewController, FloatingPanelControllerDelegate {
|
||||
class MyFloatingPanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .tip
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -321,12 +319,11 @@ class ViewController: UIViewController, FloatingPanelControllerDelegate {
|
||||
class LandscapePanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .tip
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
|
||||
func prepareLayout(surfaceView: UIView, in view: UIView) -> [NSLayoutConstraint] {
|
||||
return [
|
||||
surfaceView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 8.0),
|
||||
@@ -345,12 +342,10 @@ class LandscapePanelLayout: FloatingPanelLayout {
|
||||
class IntrinsicPanelLayout: FloatingPanelLayout {
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
let initialState: FloatingPanelState = .full
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(absoluteOffset: 0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.5, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelIntrinsicLayoutAnchor(absoluteOffset: 0, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelIntrinsicLayoutAnchor(fractionalOffset: 0.5, referenceGuide: .safeArea),
|
||||
]
|
||||
...
|
||||
}
|
||||
```
|
||||
@@ -364,14 +359,11 @@ Use `.superview` reference guide in your anchors.
|
||||
```swift
|
||||
class MyFullScreenLayout: FloatingPanelLayout {
|
||||
...
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .superview),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 16.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .superview),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 44.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -7,5 +7,19 @@ import UIKit
|
||||
public class BackdropView: UIView {
|
||||
|
||||
/// The gesture recognizer for tap gestures to dismiss a panel.
|
||||
@objc public var dismissalTapGestureRecognizer: UITapGestureRecognizer!
|
||||
///
|
||||
/// By default, this gesture recognizer is disabled as following the default behavior of iOS modalities.
|
||||
/// To dismiss a panel by tap gestures on the backdrop, `dismissalTapGestureRecognizer.isEnabled` is set to true.
|
||||
@objc public var dismissalTapGestureRecognizer: UITapGestureRecognizer
|
||||
|
||||
init() {
|
||||
dismissalTapGestureRecognizer = UITapGestureRecognizer()
|
||||
dismissalTapGestureRecognizer.isEnabled = false
|
||||
super.init(frame: .zero)
|
||||
addGestureRecognizer(dismissalTapGestureRecognizer)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
+47
-23
@@ -37,9 +37,9 @@ import UIKit
|
||||
@objc optional
|
||||
func floatingPanelShouldBeginDragging(_ fpc: FloatingPanelController) -> Bool
|
||||
|
||||
/// Called when the user drags the surface or the surface is attracted to a state anchor.
|
||||
/// Called while the user drags the surface or the surface moves to a state anchor.
|
||||
@objc optional
|
||||
func floatingPanelDidMove(_ fpc: FloatingPanelController) // any surface frame changes in dragging
|
||||
func floatingPanelDidMove(_ fpc: FloatingPanelController)
|
||||
|
||||
/// Called on start of dragging (may require some time and or distance to move)
|
||||
@objc optional
|
||||
@@ -316,7 +316,7 @@ open class FloatingPanelController: UIViewController {
|
||||
// Change a layout for the new view size
|
||||
if let newLayout = self.delegate?.floatingPanel?(self, layoutFor: size) {
|
||||
layout = newLayout
|
||||
activateLayout(forceLayout: false)
|
||||
activateLayout(forceLayout: true)
|
||||
}
|
||||
|
||||
if view.translatesAutoresizingMaskIntoConstraints {
|
||||
@@ -335,7 +335,7 @@ open class FloatingPanelController: UIViewController {
|
||||
// Change a layout for the new trait collection
|
||||
if let newLayout = self.delegate?.floatingPanel?(self, layoutFor: newCollection) {
|
||||
self.layout = newLayout
|
||||
activateLayout(forceLayout: false)
|
||||
activateLayout(forceLayout: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,8 +401,10 @@ open class FloatingPanelController: UIViewController {
|
||||
}
|
||||
|
||||
private func activateLayout(forceLayout: Bool = false) {
|
||||
floatingPanel.activateLayout(forceLayout: forceLayout,
|
||||
contentInsetAdjustmentBehavior: contentInsetAdjustmentBehavior)
|
||||
floatingPanel.activateLayout(
|
||||
forceLayout: forceLayout,
|
||||
contentInsetAdjustmentBehavior: contentInsetAdjustmentBehavior
|
||||
)
|
||||
}
|
||||
|
||||
func remove() {
|
||||
@@ -412,8 +414,14 @@ open class FloatingPanelController: UIViewController {
|
||||
guard let self = self else { return }
|
||||
self.delegate?.floatingPanelDidRemove?(self)
|
||||
}
|
||||
} else {
|
||||
} else if parent != nil {
|
||||
removePanelFromParent(animated: true)
|
||||
} else {
|
||||
hide(animated: true) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.view.removeFromSuperview()
|
||||
self.delegate?.floatingPanelDidRemove?(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,6 +447,12 @@ open class FloatingPanelController: UIViewController {
|
||||
// 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 }
|
||||
|
||||
self.update(safeAreaInsets: self.view.safeAreaInsets)
|
||||
}
|
||||
} else {
|
||||
@@ -586,6 +600,16 @@ open class FloatingPanelController: UIViewController {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/// [Experimental] Allows the panel to move as its tracking scroll view bounces.
|
||||
///
|
||||
/// This method must be called in the delegate method, `UIScrollViewDelegate.scrollViewDidScroll(_:)`,
|
||||
/// of its tracking scroll view. This method only supports a bottom positioned panel for now.
|
||||
///
|
||||
/// - TODO: Support top, left and right positioned panels.
|
||||
public func followScrollViewBouncing() {
|
||||
floatingPanel.followScrollViewBouncing()
|
||||
}
|
||||
|
||||
/// Cancel tracking the specify scroll view.
|
||||
///
|
||||
@@ -674,30 +698,30 @@ extension FloatingPanelController {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Swizzling
|
||||
|
||||
private var originalDismissImp: IMP?
|
||||
private typealias DismissFunction = @convention(c) (AnyObject, Selector, Bool, (() -> Void)?) -> Void
|
||||
extension FloatingPanelController {
|
||||
private static let dismissSwizzling: Void = {
|
||||
let aClass: AnyClass! = UIViewController.self //object_getClass(vc)
|
||||
if let imp = class_getMethodImplementation(aClass, #selector(dismiss(animated:completion:))),
|
||||
let originalAltMethod = class_getInstanceMethod(aClass, #selector(fp_original_dismiss(animated:completion:))) {
|
||||
method_setImplementation(originalAltMethod, imp)
|
||||
}
|
||||
let originalMethod = class_getInstanceMethod(aClass, #selector(dismiss(animated:completion:)))
|
||||
let swizzledMethod = class_getInstanceMethod(aClass, #selector(fp_dismiss(animated:completion:)))
|
||||
if let originalMethod = originalMethod, let swizzledMethod = swizzledMethod {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod)
|
||||
if let originalMethod = class_getInstanceMethod(aClass, #selector(dismiss(animated:completion:))),
|
||||
let swizzledImp = class_getMethodImplementation(aClass, #selector(__swizzled_dismiss(animated:completion:))) {
|
||||
originalDismissImp = method_setImplementation(originalMethod, swizzledImp)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
public extension UIViewController {
|
||||
@objc func fp_original_dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
// Implementation will be replaced by IMP of self.dismiss(animated:completion:)
|
||||
}
|
||||
@objc func fp_dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
extension UIViewController {
|
||||
@objc
|
||||
fileprivate func __swizzled_dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||
let dismissImp = unsafeBitCast(originalDismissImp, to: DismissFunction.self)
|
||||
let sel = #selector(UIViewController.dismiss(animated:completion:))
|
||||
|
||||
// Call dismiss(animated:completion:) to a content view controller
|
||||
if let fpc = parent as? FloatingPanelController {
|
||||
if fpc.presentingViewController != nil {
|
||||
self.fp_original_dismiss(animated: flag, completion: completion)
|
||||
dismissImp(self, sel, flag, completion)
|
||||
} else {
|
||||
fpc.removePanelFromParent(animated: flag, completion: completion)
|
||||
}
|
||||
@@ -707,7 +731,7 @@ public extension UIViewController {
|
||||
if let fpc = self as? FloatingPanelController {
|
||||
// When a panel is presented modally and it's not a child view controller of the presented view controller.
|
||||
if fpc.presentingViewController != nil, fpc.parent == nil {
|
||||
self.fp_original_dismiss(animated: flag, completion: completion)
|
||||
dismissImp(self, sel, flag, completion)
|
||||
} else {
|
||||
fpc.removePanelFromParent(animated: flag, completion: completion)
|
||||
}
|
||||
@@ -715,6 +739,6 @@ public extension UIViewController {
|
||||
}
|
||||
|
||||
// For other view controllers
|
||||
self.fp_original_dismiss(animated: flag, completion: completion)
|
||||
dismissImp(self, sel, flag, completion)
|
||||
}
|
||||
}
|
||||
|
||||
+111
-47
@@ -17,6 +17,19 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
didSet {
|
||||
oldValue?.panGestureRecognizer.removeTarget(self, action: nil)
|
||||
scrollView?.panGestureRecognizer.addTarget(self, action: #selector(handle(panGesture:)))
|
||||
if let cur = scrollView {
|
||||
if oldValue == nil {
|
||||
initialScrollOffset = cur.contentOffset
|
||||
scrollBounce = cur.bounces
|
||||
scrollIndictorVisible = cur.showsVerticalScrollIndicator
|
||||
}
|
||||
} else {
|
||||
if let pre = oldValue {
|
||||
pre.isDirectionalLockEnabled = false
|
||||
pre.bounces = scrollBounce
|
||||
pre.showsVerticalScrollIndicator = scrollIndictorVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +66,6 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
private var stopScrollDeceleration: Bool = false
|
||||
private var scrollBounce = false
|
||||
private var scrollIndictorVisible = false
|
||||
private var grabberAreaFrame: CGRect {
|
||||
return surfaceView.grabberAreaFrame
|
||||
}
|
||||
|
||||
// MARK: - Interface
|
||||
|
||||
@@ -63,6 +73,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
ownerVC = vc
|
||||
|
||||
surfaceView = SurfaceView()
|
||||
surfaceView.position = layout.position
|
||||
surfaceView.backgroundColor = .white
|
||||
|
||||
backdropView = BackdropView()
|
||||
@@ -85,11 +96,9 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
panGestureRecognizer.addTarget(self, action: #selector(handle(panGesture:)))
|
||||
panGestureRecognizer.delegate = self
|
||||
|
||||
// Set tap-to-dismiss in the backdrop view
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleBackdrop(tapGesture:)))
|
||||
tapGesture.isEnabled = false
|
||||
backdropView.dismissalTapGestureRecognizer = tapGesture
|
||||
backdropView.addGestureRecognizer(tapGesture)
|
||||
// Set the tap-to-dismiss action of the backdrop view.
|
||||
// It's disabled by default. See also BackdropView.dismissalTapGestureRecognizer.
|
||||
backdropView.dismissalTapGestureRecognizer.addTarget(self, action: #selector(handleBackdrop(tapGesture:)))
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -186,8 +195,10 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
// MARK: - Layout update
|
||||
|
||||
func activateLayout(forceLayout: Bool = false,
|
||||
contentInsetAdjustmentBehavior: FloatingPanelController.ContentInsetAdjustmentBehavior) {
|
||||
func activateLayout(
|
||||
forceLayout: Bool = false,
|
||||
contentInsetAdjustmentBehavior: FloatingPanelController.ContentInsetAdjustmentBehavior
|
||||
) {
|
||||
layoutAdapter.prepareLayout()
|
||||
|
||||
// preserve the current content offset if contentInsetAdjustmentBehavior is `.always`
|
||||
@@ -197,7 +208,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
layoutAdapter.updateStaticConstraint()
|
||||
layoutAdapter.activateLayout(for: state, forceLayout: true)
|
||||
layoutAdapter.activateLayout(for: state, forceLayout: forceLayout)
|
||||
|
||||
// Update the backdrop alpha only when called in `Controller.show(animated:completion:)`
|
||||
// Because that prevents a backdrop flicking just before presenting a panel(#466).
|
||||
@@ -264,7 +275,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
is UIRotationGestureRecognizer,
|
||||
is UIScreenEdgePanGestureRecognizer,
|
||||
is UIPinchGestureRecognizer:
|
||||
if grabberAreaFrame.contains(gestureRecognizer.location(in: gestureRecognizer.view)) {
|
||||
if surfaceView.grabberAreaContains(gestureRecognizer.location(in: surfaceView)) {
|
||||
return true
|
||||
}
|
||||
// all gestures of the tracking scroll view should be recognized in parallel
|
||||
@@ -295,7 +306,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
return true
|
||||
}
|
||||
|
||||
if grabberAreaFrame.contains(gestureRecognizer.location(in: gestureRecognizer.view)) {
|
||||
if surfaceView.grabberAreaContains(gestureRecognizer.location(in: surfaceView)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -323,7 +334,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
scrollGestureRecognizers.contains(otherGestureRecognizer) {
|
||||
switch otherGestureRecognizer {
|
||||
case scrollView.panGestureRecognizer:
|
||||
if grabberAreaFrame.contains(gestureRecognizer.location(in: gestureRecognizer.view)) {
|
||||
if surfaceView.grabberAreaContains(gestureRecognizer.location(in: surfaceView)) {
|
||||
return false
|
||||
}
|
||||
return allowScrollPanGesture(for: scrollView)
|
||||
@@ -351,7 +362,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
// Should begin the pan gesture without waiting the dismiss gesture of a sheet modal.
|
||||
return false
|
||||
}
|
||||
if grabberAreaFrame.contains(gestureRecognizer.location(in: gestureRecognizer.view)) {
|
||||
if surfaceView.grabberAreaContains(gestureRecognizer.location(in: surfaceView)) {
|
||||
return false
|
||||
}
|
||||
// Do not begin the pan gesture until these gestures fail
|
||||
@@ -377,11 +388,11 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
let velocity = value(of: panGesture.velocity(in: panGesture.view))
|
||||
let location = panGesture.location(in: surfaceView)
|
||||
|
||||
let belowEdgeMost = 0 > layoutAdapter.offsetFromMostExpandedAnchor + (1.0 / surfaceView.fp_displayScale)
|
||||
let insideMostExpandedAnchor = 0 > layoutAdapter.offsetFromMostExpandedAnchor + (1.0 / surfaceView.fp_displayScale)
|
||||
|
||||
log.debug("""
|
||||
scroll gesture(\(state):\(panGesture.state)) -- \
|
||||
belowTop = \(belowEdgeMost), \
|
||||
inside expanded anchor = \(insideMostExpandedAnchor), \
|
||||
interactionInProgress = \(interactionInProgress), \
|
||||
scroll offset = \(value(of: scrollView.contentOffset)), \
|
||||
location = \(value(of: location)), velocity = \(velocity)
|
||||
@@ -389,14 +400,14 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
let offsetDiff = value(of: scrollView.contentOffset - contentOffsetForPinning(of: scrollView))
|
||||
|
||||
if belowEdgeMost {
|
||||
if insideMostExpandedAnchor {
|
||||
// Scroll offset pinning
|
||||
if state == layoutAdapter.mostExpandedState {
|
||||
if interactionInProgress {
|
||||
log.debug("settle offset --", value(of: initialScrollOffset))
|
||||
stopScrolling(at: initialScrollOffset)
|
||||
} else {
|
||||
if grabberAreaFrame.contains(location) {
|
||||
if surfaceView.grabberAreaContains(location) {
|
||||
// Preserve the current content offset in moving from full.
|
||||
stopScrolling(at: initialScrollOffset)
|
||||
}
|
||||
@@ -439,7 +450,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
if state == layoutAdapter.mostExpandedState {
|
||||
// Adjust a small gap of the scroll offset just after swiping down starts in the grabber area.
|
||||
if grabberAreaFrame.contains(location), grabberAreaFrame.contains(initialLocation) {
|
||||
if surfaceView.grabberAreaContains(location), surfaceView.grabberAreaContains(initialLocation) {
|
||||
stopScrolling(at: initialScrollOffset)
|
||||
}
|
||||
}
|
||||
@@ -448,7 +459,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
switch layoutAdapter.position {
|
||||
case .top, .left:
|
||||
if velocity < 0, !allowScrollPanGesture(for: scrollView) {
|
||||
lockScrollView()
|
||||
lockScrollView(strict: true)
|
||||
}
|
||||
if velocity > 0, allowScrollPanGesture(for: scrollView) {
|
||||
unlockScrollView()
|
||||
@@ -456,7 +467,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
case .bottom, .right:
|
||||
// Hide a scroll indicator just before starting an interaction by swiping a panel down.
|
||||
if velocity > 0, !allowScrollPanGesture(for: scrollView) {
|
||||
lockScrollView()
|
||||
lockScrollView(strict: true)
|
||||
}
|
||||
// Show a scroll indicator when an animation is interrupted at the top and content is scrolled up
|
||||
if velocity < 0, allowScrollPanGesture(for: scrollView) {
|
||||
@@ -464,7 +475,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
// Adjust a small gap of the scroll offset just before swiping down starts in the grabber area,
|
||||
if grabberAreaFrame.contains(location), grabberAreaFrame.contains(initialLocation) {
|
||||
if surfaceView.grabberAreaContains(location), surfaceView.grabberAreaContains(initialLocation) {
|
||||
stopScrolling(at: initialScrollOffset)
|
||||
}
|
||||
}
|
||||
@@ -511,7 +522,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
// doesn't pass through .changed state after an interruptible animator is interrupted.
|
||||
let diff = translation - .leastNonzeroMagnitude
|
||||
layoutAdapter.updateInteractiveEdgeConstraint(diff: value(of: diff),
|
||||
overflow: true,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: behaviorAdapter.allowsRubberBanding(for:))
|
||||
}
|
||||
panningEnd(with: translation, velocity: velocity)
|
||||
@@ -572,19 +583,19 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
// When the current point is within grabber area but the initial point is not, do scroll.
|
||||
if grabberAreaFrame.contains(point), !grabberAreaFrame.contains(initialLocation) {
|
||||
if surfaceView.grabberAreaContains(point), !surfaceView.grabberAreaContains(initialLocation) {
|
||||
return true
|
||||
}
|
||||
|
||||
// When the initial point is within grabber area and the current point is out of surface, don't scroll.
|
||||
if grabberAreaFrame.contains(initialLocation), !surfaceView.frame.contains(point) {
|
||||
if surfaceView.grabberAreaContains(initialLocation), !surfaceView.frame.contains(point) {
|
||||
return false
|
||||
}
|
||||
|
||||
let scrollViewFrame = scrollView.convert(scrollView.bounds, to: surfaceView)
|
||||
guard
|
||||
scrollViewFrame.contains(initialLocation), // When the initial point not in scrollView, don't scroll.
|
||||
!grabberAreaFrame.contains(point) // When point within grabber area, don't scroll.
|
||||
!surfaceView.grabberAreaContains(point) // When point within grabber area, don't scroll.
|
||||
else {
|
||||
return false
|
||||
}
|
||||
@@ -627,7 +638,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
guard let scrollView = scrollView else { return }
|
||||
if state == layoutAdapter.mostExpandedState {
|
||||
if grabberAreaFrame.contains(location) {
|
||||
if surfaceView.grabberAreaContains(location) {
|
||||
initialScrollOffset = scrollView.contentOffset
|
||||
}
|
||||
} else {
|
||||
@@ -640,10 +651,9 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
let pre = value(of: layoutAdapter.surfaceLocation)
|
||||
let diff = value(of: translation - initialTranslation)
|
||||
let next = pre + diff
|
||||
let overflow = shouldOverflow(from: pre, to: next)
|
||||
|
||||
layoutAdapter.updateInteractiveEdgeConstraint(diff: diff,
|
||||
overflow: overflow,
|
||||
scrollingContent: shouldScrollingContentInMoving(from: pre, to: next),
|
||||
allowsRubberBanding: behaviorAdapter.allowsRubberBanding(for:))
|
||||
|
||||
let cur = value(of: layoutAdapter.surfaceLocation)
|
||||
@@ -657,32 +667,36 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private func shouldOverflow(from pre: CGFloat, to next: CGFloat) -> Bool {
|
||||
private func shouldScrollingContentInMoving(from pre: CGFloat, to next: CGFloat) -> Bool {
|
||||
// Don't allow scrolling if the initial panning location is in the grabber area.
|
||||
if surfaceView.grabberAreaContains(initialLocation) {
|
||||
return false
|
||||
}
|
||||
if let scrollView = scrollView, scrollView.panGestureRecognizer.state == .changed {
|
||||
switch layoutAdapter.position {
|
||||
case .top:
|
||||
if pre > .zero, pre < next,
|
||||
scrollView.contentSize.height > scrollView.bounds.height || scrollView.alwaysBounceVertical {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
case .left:
|
||||
if pre > .zero, pre < next,
|
||||
scrollView.contentSize.width > scrollView.bounds.width || scrollView.alwaysBounceHorizontal {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
case .bottom:
|
||||
if pre > .zero, pre > next,
|
||||
scrollView.contentSize.height > scrollView.bounds.height || scrollView.alwaysBounceVertical {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
case .right:
|
||||
if pre > .zero, pre > next,
|
||||
scrollView.contentSize.width > scrollView.bounds.width || scrollView.alwaysBounceHorizontal {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
private func panningEnd(with translation: CGPoint, velocity: CGPoint) {
|
||||
@@ -697,7 +711,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
if stopScrollDeceleration {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
|
||||
self.stopScrolling(at: self.initialScrollOffset)
|
||||
}
|
||||
}
|
||||
@@ -785,19 +799,24 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
initialSurfaceLocation = layoutAdapter.surfaceLocation
|
||||
if state == layoutAdapter.mostExpandedState, let scrollView = scrollView {
|
||||
if grabberAreaFrame.contains(location) {
|
||||
if surfaceView.grabberAreaContains(location) {
|
||||
initialScrollOffset = scrollView.contentOffset
|
||||
} else {
|
||||
initialScrollOffset = contentOffsetForPinning(of: scrollView)
|
||||
let offsetDiff = scrollView.contentOffset - contentOffsetForPinning(of: scrollView)
|
||||
let pinningOffset = contentOffsetForPinning(of: scrollView)
|
||||
|
||||
// `scrollView.contentOffset` can be a value in [-30, 0) at this time by `allowScrollPanGesture(for:)`.
|
||||
// Therefore the initial scroll offset must be reset to the pinning offset. Otherwise, the following
|
||||
// `Fit the surface bounds` logic don't working and also the scroll content offset can be invalid.
|
||||
initialScrollOffset = pinningOffset
|
||||
|
||||
// Fit the surface bounds to a scroll offset content by startInteraction(at:offset:)
|
||||
let offsetDiff = scrollView.contentOffset - pinningOffset
|
||||
switch layoutAdapter.position {
|
||||
case .top, .left:
|
||||
// Fit the surface bounds to a scroll offset content by startInteraction(at:offset:)
|
||||
if value(of: offsetDiff) > 0 {
|
||||
offset = -offsetDiff
|
||||
}
|
||||
case .bottom, .right:
|
||||
// Fit the surface bounds to a scroll offset content by startInteraction(at:offset:)
|
||||
if value(of: offsetDiff) < 0 {
|
||||
offset = -offsetDiff
|
||||
}
|
||||
@@ -911,6 +930,8 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
""")
|
||||
if finished, state == layoutAdapter.mostExpandedState, abs(layoutAdapter.offsetFromMostExpandedAnchor) <= 1.0 {
|
||||
unlockScrollView()
|
||||
} else if finished, shouldLooselyLockScrollView {
|
||||
unlockScrollView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,6 +939,10 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
return layoutAdapter.position.mainLocation(point)
|
||||
}
|
||||
|
||||
func value(of size: CGSize) -> CGFloat {
|
||||
return layoutAdapter.position.mainDimension(size)
|
||||
}
|
||||
|
||||
func setValue(_ newValue: CGPoint, to point: inout CGPoint) {
|
||||
switch layoutAdapter.position {
|
||||
case .top, .bottom:
|
||||
@@ -989,7 +1014,23 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
|
||||
// MARK: - ScrollView handling
|
||||
|
||||
private func lockScrollView() {
|
||||
func followScrollViewBouncing() {
|
||||
guard let scrollView = scrollView else {
|
||||
return
|
||||
}
|
||||
let contentOffset = scrollView.contentOffset.y
|
||||
guard contentOffset < 0, layoutAdapter.position == .bottom, state == layoutAdapter.mostExpandedState else {
|
||||
if surfaceView.transform != .identity {
|
||||
surfaceView.transform = .identity
|
||||
scrollView.transform = .identity
|
||||
}
|
||||
return
|
||||
}
|
||||
surfaceView.transform = CGAffineTransform(translationX: 0, y: -contentOffset)
|
||||
scrollView.transform = CGAffineTransform(translationX: 0, y: contentOffset)
|
||||
}
|
||||
|
||||
private func lockScrollView(strict: Bool = false) {
|
||||
guard let scrollView = scrollView else { return }
|
||||
|
||||
if scrollView.isLocked {
|
||||
@@ -998,11 +1039,19 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
}
|
||||
log.debug("lock scroll view")
|
||||
|
||||
scrollBounce = scrollView.bounces
|
||||
scrollIndictorVisible = scrollView.showsVerticalScrollIndicator
|
||||
|
||||
if !strict, shouldLooselyLockScrollView {
|
||||
// Don't change its `bounces` property. If it's changed, it will cause its scroll content offset jump at
|
||||
// the most expanded anchor position while seamlessly scrolling content. This problem only occurs where its
|
||||
// content mode is `.fitToBounds` and the tracking scroll content is smaller than the content view size.
|
||||
// The reason why is because `bounces` prop change leads to the "content frame" change on `.fitToBounds`.
|
||||
// See also https://github.com/scenee/FloatingPanel/issues/524.
|
||||
} else {
|
||||
scrollBounce = scrollView.bounces
|
||||
scrollView.bounces = false
|
||||
}
|
||||
scrollView.isDirectionalLockEnabled = true
|
||||
scrollView.bounces = false
|
||||
scrollView.showsVerticalScrollIndicator = false
|
||||
}
|
||||
|
||||
@@ -1010,16 +1059,31 @@ class Core: NSObject, UIGestureRecognizerDelegate {
|
||||
guard let scrollView = scrollView, scrollView.isLocked else { return }
|
||||
log.debug("unlock scroll view")
|
||||
|
||||
scrollView.isDirectionalLockEnabled = false
|
||||
scrollView.bounces = scrollBounce
|
||||
scrollView.isDirectionalLockEnabled = false
|
||||
scrollView.showsVerticalScrollIndicator = scrollIndictorVisible
|
||||
}
|
||||
|
||||
private var shouldLooselyLockScrollView: Bool {
|
||||
var isSmallScrollContentAndFitToBoundsMode: Bool {
|
||||
if ownerVC?.contentMode == .fitToBounds, let scrollView = scrollView,
|
||||
value(of: scrollView.contentSize) < value(of: scrollView.bounds.size) - min(layoutAdapter.offsetFromMostExpandedAnchor, 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return isSmallScrollContentAndFitToBoundsMode
|
||||
}
|
||||
|
||||
private func stopScrolling(at contentOffset: CGPoint) {
|
||||
// Must use setContentOffset(_:animated) to force-stop deceleration
|
||||
guard let scrollView = scrollView else { return }
|
||||
var offset = scrollView.contentOffset
|
||||
setValue(contentOffset, to: &offset)
|
||||
if contentOffset.y >= 0 {
|
||||
setValue(contentOffset, to: &offset)
|
||||
} else {
|
||||
offset = CGPoint(x: 0, y: 0)
|
||||
}
|
||||
scrollView.setContentOffset(offset, animated: false)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# ``FloatingPanel``
|
||||
|
||||
The new interface displays the related contents and utilities in parallel as a user wants.
|
||||
Create a user interface to display the related content and utilities alongside the main content.
|
||||
|
||||
## Overview
|
||||
|
||||
FloatingPanel is a simple and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app.
|
||||
The new interface displays the related contents and utilities in parallel as a user wants.
|
||||
|
||||
FloatingPanel is a simple and easy-to-use UI component designed for a user interface featured in the Apple Maps, Shortcuts and Stocks app.
|
||||
The user interface displays related content and utilities alongside the main content.
|
||||
|
||||
|
||||
## Topics
|
||||
@@ -44,6 +45,7 @@ The new interface displays the related contents and utilities in parallel as a u
|
||||
- ``FloatingPanelPosition``
|
||||
- ``FloatingPanelReferenceEdge``
|
||||
- ``FloatingPanelLayoutReferenceGuide``
|
||||
- ``FloatingPanelLayoutContentBoundingGuide``
|
||||
|
||||
### Behaviors
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.5.1</string>
|
||||
<string>2.6.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
|
||||
+37
-7
@@ -92,6 +92,9 @@ class LayoutAdapter {
|
||||
|
||||
private var staticConstraint: NSLayoutConstraint?
|
||||
|
||||
/// A layout constraint to limit the content size in ``FloatingPanelAdaptiveLayoutAnchor``.
|
||||
private var contentBoundingConstraint: NSLayoutConstraint?
|
||||
|
||||
private var anchorStates: Set<FloatingPanelState> {
|
||||
return Set(layout.anchors.keys)
|
||||
}
|
||||
@@ -330,12 +333,27 @@ class LayoutAdapter {
|
||||
if anchor.referenceGuide == .safeArea {
|
||||
referenceBoundsLength += position.inset(safeAreaInsets)
|
||||
}
|
||||
return dimension - diff
|
||||
let maxPosition: CGFloat = {
|
||||
if let maxBounds = anchor.contentBoundingGuide.maxBounds(vc) {
|
||||
return layout.position.mainLocation(maxBounds.origin)
|
||||
+ layout.position.mainDimension(maxBounds.size)
|
||||
} else {
|
||||
return .infinity
|
||||
}
|
||||
}()
|
||||
return min(dimension - diff, maxPosition)
|
||||
case .bottom, .right:
|
||||
if anchor.referenceGuide == .safeArea {
|
||||
referenceBoundsLength -= position.inset(safeAreaInsets)
|
||||
}
|
||||
return referenceBoundsLength - dimension + diff
|
||||
let minPosition: CGFloat = {
|
||||
if let maxBounds = anchor.contentBoundingGuide.maxBounds(vc) {
|
||||
return layout.position.mainLocation(maxBounds.origin)
|
||||
} else {
|
||||
return -(.infinity)
|
||||
}
|
||||
}()
|
||||
return max(referenceBoundsLength - dimension + diff, minPosition)
|
||||
}
|
||||
case let anchor as FloatingPanelLayoutAnchor:
|
||||
let referenceBounds = anchor.referenceGuide == .safeArea ? bounds.inset(by: safeAreaInsets) : bounds
|
||||
@@ -629,8 +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(constraint: staticConstraint)
|
||||
NSLayoutConstraint.deactivate([staticConstraint, contentBoundingConstraint].compactMap{ $0 })
|
||||
staticConstraint = nil
|
||||
contentBoundingConstraint = nil
|
||||
|
||||
if vc.contentMode == .fitToBounds {
|
||||
surfaceView.containerOverflow = 0
|
||||
@@ -654,7 +673,18 @@ class LayoutAdapter {
|
||||
constant = 0.0
|
||||
}
|
||||
let baseAnchor = position.mainDimensionAnchor(anchor.contentLayoutGuide)
|
||||
staticConstraint = surfaceAnchor.constraint(equalTo: baseAnchor, constant: constant)
|
||||
if let boundingLayoutGuide = anchor.contentBoundingGuide.layoutGuide(vc) {
|
||||
if anchor.isAbsolute {
|
||||
contentBoundingConstraint = baseAnchor.constraint(lessThanOrEqualTo: position.mainDimensionAnchor(boundingLayoutGuide),
|
||||
constant: anchor.offset)
|
||||
} else {
|
||||
contentBoundingConstraint = baseAnchor.constraint(lessThanOrEqualTo: position.mainDimensionAnchor(boundingLayoutGuide),
|
||||
multiplier: anchor.offset)
|
||||
}
|
||||
staticConstraint = surfaceAnchor.constraint(lessThanOrEqualTo: baseAnchor, constant: constant)
|
||||
} else {
|
||||
staticConstraint = surfaceAnchor.constraint(equalTo: baseAnchor, constant: constant)
|
||||
}
|
||||
default:
|
||||
switch position {
|
||||
case .top, .left:
|
||||
@@ -673,12 +703,12 @@ class LayoutAdapter {
|
||||
staticConstraint?.identifier = "FloatingPanel-static-width"
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate(constraint: staticConstraint)
|
||||
NSLayoutConstraint.activate([staticConstraint, contentBoundingConstraint].compactMap{ $0 })
|
||||
|
||||
surfaceView.containerOverflow = position.mainDimension(vc.view.bounds.size)
|
||||
}
|
||||
|
||||
func updateInteractiveEdgeConstraint(diff: CGFloat, overflow: Bool, allowsRubberBanding: (UIRectEdge) -> Bool) {
|
||||
func updateInteractiveEdgeConstraint(diff: CGFloat, scrollingContent: Bool, allowsRubberBanding: (UIRectEdge) -> Bool) {
|
||||
defer {
|
||||
log.debug("update surface location = \(surfaceLocation)")
|
||||
}
|
||||
@@ -701,7 +731,7 @@ class LayoutAdapter {
|
||||
const = maxConst + rubberBandEffect(for: buffer, base: base)
|
||||
}
|
||||
|
||||
if overflow == false {
|
||||
if scrollingContent {
|
||||
const = min(max(const, minConst), maxConst)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@ import UIKit
|
||||
///
|
||||
/// The inset is an amount to inset a panel from an edge of the reference guide. The edge refers to a panel
|
||||
/// positioning.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - absoluteOffset: 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) {
|
||||
self.inset = absoluteInset
|
||||
self.referenceGuide = referenceGuide
|
||||
@@ -27,6 +32,11 @@ import UIKit
|
||||
/// The inset is an amount to inset a panel from the edge of the specified reference guide. The value is
|
||||
/// a floating-point number in the range 0.0 to 1.0, where 0.0 represents zero distance from the edge and
|
||||
/// 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.
|
||||
/// - 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) {
|
||||
self.inset = fractionalInset
|
||||
self.referenceGuide = referenceGuide
|
||||
@@ -49,7 +59,7 @@ public extension FloatingPanelLayoutAnchor {
|
||||
case .left:
|
||||
return layoutConstraints(layoutGuide, for: vc.surfaceView.rightAnchor)
|
||||
case .bottom:
|
||||
return layoutConstraints(layoutGuide, for: vc.surfaceView.topAnchor)
|
||||
return layoutConstraints(layoutGuide, for: vc.surfaceView.topAnchor)
|
||||
case .right:
|
||||
return layoutConstraints(layoutGuide, for: vc.surfaceView.leftAnchor)
|
||||
}
|
||||
@@ -101,6 +111,10 @@ public extension FloatingPanelLayoutAnchor {
|
||||
///
|
||||
/// The offset is an amount to offset a position of panel that displays the entire content from an edge of
|
||||
/// the reference guide. The edge refers to a panel positioning.
|
||||
///
|
||||
/// - 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
|
||||
self.referenceGuide = referenceGuide
|
||||
@@ -111,6 +125,10 @@ public extension FloatingPanelLayoutAnchor {
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// - 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
|
||||
self.referenceGuide = referenceGuide
|
||||
@@ -144,37 +162,72 @@ 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.
|
||||
@objc public init(absoluteOffset offset: CGFloat, contentLayout: UILayoutGuide, referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea) {
|
||||
///
|
||||
/// ``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. Normally both of ``referenceGuide`` and ``contentBoundingGuide`` are specified with the same rectangle area.
|
||||
///
|
||||
/// - 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 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.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.
|
||||
@objc public init(fractionalOffset offset: CGFloat, contentLayout: UILayoutGuide, referenceGuide: FloatingPanelLayoutReferenceGuide = .safeArea) {
|
||||
///
|
||||
/// ``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. Normally both of ``referenceGuide`` and ``contentBoundingGuide`` are specified with the same rectangle area.
|
||||
///
|
||||
/// - 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 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.contentBoundingGuide = contentBoundingGuide
|
||||
self.isAbsolute = false
|
||||
}
|
||||
fileprivate let offset: CGFloat
|
||||
fileprivate let isAbsolute: Bool
|
||||
let offset: CGFloat
|
||||
let isAbsolute: Bool
|
||||
let contentLayoutGuide: UILayoutGuide
|
||||
@objc public let referenceGuide: FloatingPanelLayoutReferenceGuide
|
||||
@objc public let contentBoundingGuide: FloatingPanelLayoutContentBoundingGuide
|
||||
}
|
||||
|
||||
public extension FloatingPanelAdaptiveLayoutAnchor {
|
||||
func layoutConstraints(_ vc: FloatingPanelController, for position: FloatingPanelPosition) -> [NSLayoutConstraint] {
|
||||
var constraints = [NSLayoutConstraint]()
|
||||
|
||||
let layoutGuide = referenceGuide.layoutGuide(vc: vc)
|
||||
let offsetConstraint: NSLayoutConstraint
|
||||
let offsetAnchor: NSLayoutDimension
|
||||
switch position {
|
||||
case .top:
|
||||
@@ -187,10 +240,13 @@ public extension FloatingPanelAdaptiveLayoutAnchor {
|
||||
offsetAnchor = vc.surfaceView.leftAnchor.anchorWithOffset(to: layoutGuide.rightAnchor)
|
||||
}
|
||||
if isAbsolute {
|
||||
return [offsetAnchor.constraint(equalTo: position.mainDimensionAnchor(contentLayoutGuide), constant: -offset)]
|
||||
offsetConstraint = offsetAnchor.constraint(equalTo: position.mainDimensionAnchor(contentLayoutGuide), constant: -offset)
|
||||
} else {
|
||||
return [offsetAnchor.constraint(equalTo: position.mainDimensionAnchor(contentLayoutGuide), multiplier: (1 - offset))]
|
||||
offsetConstraint = offsetAnchor.constraint(equalTo: position.mainDimensionAnchor(contentLayoutGuide), multiplier: (1 - offset))
|
||||
}
|
||||
constraints.append(offsetConstraint)
|
||||
|
||||
return constraints
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ extension FloatingPanelReferenceEdge {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constants that specify a layout guide to lay out a panel.
|
||||
/// A representation to specify a rectangular area to lay out a panel.
|
||||
@objc public enum FloatingPanelLayoutReferenceGuide: Int {
|
||||
case superview = 0
|
||||
case safeArea = 1
|
||||
@@ -43,3 +43,34 @@ extension FloatingPanelLayoutReferenceGuide {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 FloatingPanelLayoutContentBoundingGuide {
|
||||
func layoutGuide(_ fpc: FloatingPanelController) -> LayoutGuideProvider? {
|
||||
switch self {
|
||||
case .superview:
|
||||
return fpc.view
|
||||
case .safeArea:
|
||||
return fpc.fp_safeAreaLayoutGuide
|
||||
case .none:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
func maxBounds(_ fpc: FloatingPanelController) -> CGRect? {
|
||||
switch self {
|
||||
case .superview:
|
||||
return fpc.view.bounds
|
||||
case .safeArea:
|
||||
return fpc.view.bounds.inset(by: fpc.fp_safeAreaInsets)
|
||||
case .none:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,7 +54,12 @@ public class SurfaceAppearance: NSObject {
|
||||
///
|
||||
/// Defaults to `.circular`.
|
||||
@available(iOS 13.0, *)
|
||||
public lazy var cornerCurve: CALayerCornerCurve = .circular
|
||||
public var cornerCurve: CALayerCornerCurve {
|
||||
get { _cornerCurve ?? .circular }
|
||||
set { _cornerCurve = newValue }
|
||||
}
|
||||
|
||||
private var _cornerCurve: CALayerCornerCurve?
|
||||
|
||||
/// An array of shadows used to create drop shadows underneath a surface view.
|
||||
public var shadows: [Shadow] = [Shadow()]
|
||||
@@ -442,4 +447,22 @@ public class SurfaceView: UIView {
|
||||
func hasStackView() -> Bool {
|
||||
return contentView?.subviews.reduce(false) { $0 || ($1 is UIStackView) } ?? false
|
||||
}
|
||||
|
||||
func grabberAreaContains(_ location: CGPoint) -> Bool {
|
||||
// Sometimes a dragging finger's location is out of surface frame.
|
||||
let cappedLocation: CGPoint
|
||||
// Because the maximum width / height is out of bounds in CGRect.contains(_:)
|
||||
let adjustment = 1 / fp_displayScale
|
||||
switch position {
|
||||
case .top:
|
||||
cappedLocation = CGPoint(x: location.x, y: min(location.y, bounds.height - adjustment))
|
||||
case .left:
|
||||
cappedLocation = CGPoint(x: min(location.x, bounds.width - adjustment), y: location.y)
|
||||
case .bottom:
|
||||
cappedLocation = CGPoint(x: location.x, y: max(location.y, 0))
|
||||
case .right:
|
||||
cappedLocation = CGPoint(x: max(location.x, 0), y: location.y)
|
||||
}
|
||||
return grabberAreaFrame.contains(cappedLocation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,10 @@ class ModalPresentTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
fpc?.suspendTransitionAnimator(false)
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||
}
|
||||
return fpc.transitionAnimator!
|
||||
guard let transitionAnimator = fpc.transitionAnimator else {
|
||||
fatalError("The panel state must be `hidden` but it is `\(fpc.state)`")
|
||||
}
|
||||
return transitionAnimator
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
|
||||
@@ -22,7 +22,11 @@ class ControllerTests: XCTestCase {
|
||||
}
|
||||
|
||||
func test_addPanel() {
|
||||
guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else { fatalError() }
|
||||
let rootVC = UIViewController()
|
||||
rootVC.loadViewIfNeeded()
|
||||
rootVC.view.bounds = .init(origin: .zero, size: .init(width: 390, height: 844))
|
||||
|
||||
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.addPanel(toParent: rootVC)
|
||||
XCTAssertEqual(fpc.surfaceLocation.y, fpc.surfaceLocation(for: .half).y)
|
||||
@@ -314,7 +318,6 @@ class ControllerTests: XCTestCase {
|
||||
fpc.move(to: .full, animated: false)
|
||||
XCTAssertEqual(fpc.surfaceView.frame.height, fpc.view.bounds.height - fpc.surfaceLocation(for: .full).y)
|
||||
fpc.move(to: .half, animated: false)
|
||||
print(1 / fpc.surfaceView.fp_displayScale)
|
||||
XCTAssertEqual(fpc.surfaceView.frame.height, fpc.view.bounds.height - fpc.surfaceLocation(for: .half).y)
|
||||
fpc.move(to: .tip, animated: false)
|
||||
XCTAssertEqual(fpc.surfaceView.frame.height, fpc.view.bounds.height - fpc.surfaceLocation(for: .tip).y)
|
||||
@@ -336,8 +339,7 @@ private class MyZombieViewController: UIViewController, FloatingPanelLayout, Flo
|
||||
return .half
|
||||
}
|
||||
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: UIScreen.main.bounds.height == 667.0 ? 18.0 : 16.0,
|
||||
edge: .top,
|
||||
referenceGuide: .superview),
|
||||
@@ -347,6 +349,5 @@ private class MyZombieViewController: UIViewController, FloatingPanelLayout, Flo
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 60.0,
|
||||
edge: .bottom,
|
||||
referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+91
-44
@@ -61,9 +61,8 @@ class CoreTests: XCTestCase {
|
||||
class FloatingPanelLayout1Positions: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .full
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview)]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] =
|
||||
[.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview)]
|
||||
}
|
||||
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
@@ -106,12 +105,10 @@ class CoreTests: XCTestCase {
|
||||
class FloatingPanelLayout2Positions: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .half
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
@@ -198,26 +195,41 @@ class CoreTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
let fpc = FloatingPanelController()
|
||||
class BackdropTestLayout2: FloatingPanelTestLayout {
|
||||
func backdropAlpha(for state: FloatingPanelState) -> CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
class TestDelegate: FloatingPanelControllerDelegate {
|
||||
var layout: FloatingPanelLayout = BackdropTestLayout2()
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout { layout }
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor size: CGSize) -> FloatingPanelLayout { layout }
|
||||
}
|
||||
func _floor(_ alpha: CGFloat) -> CGFloat {
|
||||
return floor(fpc.backdropView.alpha * 1e+06) / 1e+06
|
||||
}
|
||||
|
||||
let delegate = TestDelegate()
|
||||
let fpc = FloatingPanelController(delegate: delegate)
|
||||
fpc.layout = BackdropTestLayout()
|
||||
|
||||
fpc.showForTest()
|
||||
|
||||
fpc.move(to: .full, animated: false)
|
||||
XCTAssertEqual(floor(fpc.backdropView.alpha * 1000_000) / 1000_000, 0.3)
|
||||
XCTAssertEqual(_floor(fpc.backdropView.alpha), 0.3)
|
||||
|
||||
fpc.move(to: .half, animated: false)
|
||||
XCTAssertEqual(fpc.backdropView.alpha, 0.0)
|
||||
|
||||
fpc.move(to: .tip, animated: false)
|
||||
XCTAssertEqual(floor(fpc.backdropView.alpha * 1000_000) / 1000_000, 0.3)
|
||||
XCTAssertEqual(_floor(fpc.backdropView.alpha), 0.3)
|
||||
|
||||
let exp1 = expectation(description: "move to full with animation")
|
||||
fpc.move(to: .full, animated: true) {
|
||||
exp1.fulfill()
|
||||
}
|
||||
wait(for: [exp1], timeout: 1.0)
|
||||
XCTAssertEqual(floor(fpc.backdropView.alpha * 1000_000) / 1000_000, 0.3)
|
||||
XCTAssertEqual(_floor(fpc.backdropView.alpha), 0.3)
|
||||
|
||||
let exp2 = expectation(description: "move to half with animation")
|
||||
fpc.move(to: .half, animated: true) {
|
||||
@@ -226,23 +238,66 @@ class CoreTests: XCTestCase {
|
||||
wait(for: [exp2], timeout: 1.0)
|
||||
XCTAssertEqual(fpc.backdropView.alpha, 0.0)
|
||||
|
||||
// Test a content mode change of FloatingPanelController
|
||||
|
||||
let exp3 = expectation(description: "move to tip with animation")
|
||||
fpc.move(to: .tip, animated: true) {
|
||||
exp3.fulfill()
|
||||
}
|
||||
fpc.contentMode = .fitToBounds
|
||||
XCTAssertEqual(fpc.backdropView.alpha, 0.0) // Must not affect the backdrop alpha by changing the content mode
|
||||
XCTAssertEqual(fpc.backdropView.alpha, 0.0) // Must not affect the backdrop alpha by changing the content mode
|
||||
wait(for: [exp3], timeout: 1.0)
|
||||
XCTAssertEqual(floor(fpc.backdropView.alpha * 1000_000) / 1000_000, 0.3)
|
||||
XCTAssertEqual(_floor(fpc.backdropView.alpha), 0.3)
|
||||
|
||||
// Test a size class change of FloatingPanelController.view
|
||||
|
||||
fpc.move(to: .full, animated: false)
|
||||
XCTAssertEqual(_floor(fpc.backdropView.alpha), 0.3)
|
||||
fpc.willTransition(to: UITraitCollection(horizontalSizeClass: .regular), with: MockTransitionCoordinator())
|
||||
XCTAssertEqual(fpc.backdropView.alpha, 0.0) // Must update the alpha by BackdropTestLayout2 in TestDelegate.
|
||||
|
||||
// Test a view size change of FloatingPanelController.view
|
||||
|
||||
fpc.move(to: .full, animated: false)
|
||||
delegate.layout = BackdropTestLayout()
|
||||
fpc.invalidateLayout()
|
||||
XCTAssertEqual(_floor(fpc.backdropView.alpha), 0.3)
|
||||
|
||||
delegate.layout = BackdropTestLayout2()
|
||||
fpc.viewWillTransition(to: CGSize.zero, with: MockTransitionCoordinator())
|
||||
XCTAssertEqual(fpc.backdropView.alpha, 0.0) // Must update the alpha by BackdropTestLayout2 in TestDelegate.
|
||||
}
|
||||
|
||||
func test_initial_surface_position() {
|
||||
class FloatingPanelTestDelegate: FloatingPanelControllerDelegate {
|
||||
class Layout: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .full
|
||||
let position: FloatingPanelPosition = .top
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring]
|
||||
= [.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .bottom, referenceGuide: .superview)]
|
||||
}
|
||||
func floatingPanel(_ fpc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout {
|
||||
Layout()
|
||||
}
|
||||
}
|
||||
do {
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
let fpc = FloatingPanelController(delegate: delegate)
|
||||
XCTAssertEqual(fpc.surfaceView.position, .top)
|
||||
}
|
||||
do {
|
||||
let fpc = FloatingPanelController()
|
||||
fpc.layout = FloatingPanelTestDelegate.Layout()
|
||||
XCTAssertEqual(fpc.surfaceView.position, .top)
|
||||
}
|
||||
}
|
||||
|
||||
func test_targetPosition_1positions() {
|
||||
class FloatingPanelLayout1Positions: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .full
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview)]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring]
|
||||
= [.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview)]
|
||||
}
|
||||
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
@@ -269,12 +324,10 @@ class CoreTests: XCTestCase {
|
||||
class FloatingPanelLayout2Positions: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .half
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
@@ -326,12 +379,10 @@ class CoreTests: XCTestCase {
|
||||
class FloatingPanelLayout2Positions: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .hidden
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
@@ -689,13 +740,11 @@ class CoreTests: XCTestCase {
|
||||
class FloatingPanelLayout3PositionsWithHidden: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .hidden
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 20.0, edge: .top, referenceGuide: .superview),
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
let fpc = FloatingPanelController(delegate: delegate)
|
||||
@@ -721,13 +770,11 @@ class CoreTests: XCTestCase {
|
||||
class FloatingPanelLayout3Positions: FloatingPanelLayout {
|
||||
let initialState: FloatingPanelState = .hidden
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
var anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 60.0, edge: .bottom, referenceGuide: .superview),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState : FloatingPanelLayoutAnchoring] = [
|
||||
.half: FloatingPanelLayoutAnchor(absoluteInset: 250.0, edge: .bottom, referenceGuide: .superview),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 60.0, edge: .bottom, referenceGuide: .superview),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
|
||||
let delegate = FloatingPanelTestDelegate()
|
||||
|
||||
+40
-51
@@ -17,23 +17,19 @@ class LayoutTests: XCTestCase {
|
||||
XCTAssertEqual(fpc.floatingPanel.layoutAdapter.leastExpandedState, .tip)
|
||||
|
||||
class FloatingPanelLayoutWithHidden: FloatingPanelLayout {
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview)
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .top, referenceGuide: .safeArea),
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview)
|
||||
]
|
||||
let initialState: FloatingPanelState = .hidden
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
}
|
||||
class FloatingPanelLayout2Positions: FloatingPanelLayout {
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.half: FloatingPanelLayoutAnchor(fractionalInset: 0.5, edge: .bottom, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: 69.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
let initialState: FloatingPanelState = .tip
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
}
|
||||
@@ -138,31 +134,31 @@ class LayoutTests: XCTestCase {
|
||||
var next: CGFloat
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: -100.0,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos + 100.0)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: tipPos - fullPos,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, tipPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: tipPos - fullPos + 100.0,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, tipPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: tipPos - fullPos + 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, tipPos + 100.0)
|
||||
@@ -190,31 +186,31 @@ class LayoutTests: XCTestCase {
|
||||
var next: CGFloat
|
||||
pre = fpc.surfaceLocation.y
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: -100.0,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, pre)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, tipPos + 100.0)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: fullPos - tipPos,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: fullPos - tipPos + 100,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: fullPos - tipPos + 100,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos + 100.0)
|
||||
@@ -224,12 +220,10 @@ class LayoutTests: XCTestCase {
|
||||
|
||||
func test_updateInteractiveEdgeConstraintWithHidden() {
|
||||
class FloatingPanelLayout2Positions: FloatingPanelLayout {
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
return [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .bottom, referenceGuide: .superview),
|
||||
]
|
||||
let initialState: FloatingPanelState = .hidden
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
}
|
||||
@@ -245,19 +239,19 @@ class LayoutTests: XCTestCase {
|
||||
var next: CGFloat
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: -100.0,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: -100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos - 100.0)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: hiddenPos - fullPos + 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, hiddenPos + 100.0)
|
||||
@@ -267,12 +261,10 @@ class LayoutTests: XCTestCase {
|
||||
|
||||
func test_updateInteractiveEdgeConstraintWithHidden_bottomEdge() {
|
||||
class FloatingPanelLayout2Positions: FloatingPanelLayout {
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
[
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .top, referenceGuide: .superview),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: 18.0, edge: .bottom, referenceGuide: .safeArea),
|
||||
.hidden: FloatingPanelLayoutAnchor(absoluteInset: 0, edge: .top, referenceGuide: .superview),
|
||||
]
|
||||
let initialState: FloatingPanelState = .hidden
|
||||
let position: FloatingPanelPosition = .top
|
||||
}
|
||||
@@ -288,19 +280,19 @@ class LayoutTests: XCTestCase {
|
||||
var next: CGFloat
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: 100.0,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos + 100.0)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: hiddenPos - fullPos + 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, hiddenPos + 100.0)
|
||||
@@ -310,12 +302,10 @@ class LayoutTests: XCTestCase {
|
||||
|
||||
func test_updateInteractiveTopConstraintWithMinusInsets() {
|
||||
class FloatingPanelLayoutMinusInsets: FloatingPanelLayout {
|
||||
var anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] {
|
||||
[
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: -200, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: -200, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
}
|
||||
let anchors: [FloatingPanelState: FloatingPanelLayoutAnchoring] = [
|
||||
.full: FloatingPanelLayoutAnchor(absoluteInset: -200, edge: .top, referenceGuide: .safeArea),
|
||||
.tip: FloatingPanelLayoutAnchor(absoluteInset: -200, edge: .bottom, referenceGuide: .safeArea),
|
||||
]
|
||||
let initialState: FloatingPanelState = .full
|
||||
let position: FloatingPanelPosition = .bottom
|
||||
}
|
||||
@@ -328,19 +318,19 @@ class LayoutTests: XCTestCase {
|
||||
|
||||
var next: CGFloat
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: -100.0,
|
||||
overflow: false,
|
||||
scrollingContent: true,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: -100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, fullPos - 100)
|
||||
|
||||
fpc.floatingPanel.layoutAdapter.updateInteractiveEdgeConstraint(diff: tipPos - fullPos + 100.0,
|
||||
overflow: true,
|
||||
scrollingContent: false,
|
||||
allowsRubberBanding: fpc.floatingPanel.behaviorAdapter.allowsRubberBanding(for:))
|
||||
next = fpc.surfaceLocation.y
|
||||
XCTAssertEqual(next, tipPos + 100)
|
||||
@@ -474,7 +464,6 @@ class LayoutTests: XCTestCase {
|
||||
if #available(iOS 11, *) {
|
||||
XCTAssertEqual(c.secondAnchor, prop.result.secondAnchor, line: UInt(prop.result.0))
|
||||
}
|
||||
print(c)
|
||||
}
|
||||
}
|
||||
func test_layoutAnchor_bottomPosition() {
|
||||
|
||||
@@ -228,4 +228,88 @@ class SurfaceViewTests: XCTestCase {
|
||||
XCTAssert(surface.containerView.layer.borderColor == UIColor.red.cgColor)
|
||||
XCTAssert(surface.containerView.layer.borderWidth == 3.0)
|
||||
}
|
||||
|
||||
func test_surfaceView_grabberArea() {
|
||||
let sv = SurfaceView()
|
||||
sv.bounds = .init(x: 0, y: 0, width: 375, height: 500)
|
||||
sv.grabberAreaOffset = 44.0
|
||||
// Top
|
||||
do {
|
||||
sv.position = .top
|
||||
XCTAssertEqual(sv.grabberAreaFrame,
|
||||
.init(x: 0,
|
||||
y: sv.bounds.height - sv.grabberAreaOffset,
|
||||
width: sv.bounds.width,
|
||||
height: sv.grabberAreaOffset))
|
||||
}
|
||||
// Bottom
|
||||
do {
|
||||
sv.position = .bottom
|
||||
XCTAssertEqual(sv.grabberAreaFrame,
|
||||
.init(x: 0,
|
||||
y: 0,
|
||||
width: sv.bounds.width,
|
||||
height: sv.grabberAreaOffset))
|
||||
}
|
||||
// Left
|
||||
do {
|
||||
sv.position = .left
|
||||
XCTAssertEqual(sv.grabberAreaFrame,
|
||||
.init(x: sv.bounds.width - sv.grabberAreaOffset,
|
||||
y: 0,
|
||||
width: sv.grabberAreaOffset,
|
||||
height: sv.bounds.height))
|
||||
}
|
||||
// Right
|
||||
do {
|
||||
sv.position = .right
|
||||
XCTAssertEqual(sv.grabberAreaFrame,
|
||||
.init(x: 0,
|
||||
y: 0,
|
||||
width: sv.grabberAreaOffset,
|
||||
height: sv.bounds.height))
|
||||
}
|
||||
}
|
||||
|
||||
func test_surfaceView_grabberAreaDetection() {
|
||||
let sv = SurfaceView()
|
||||
sv.bounds = .init(x: 0, y: 0, width: 375, height: 500)
|
||||
// Top
|
||||
do {
|
||||
sv.position = .top
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: 0, y: sv.bounds.height)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width / 2, y: sv.bounds.height)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width / 2, y: sv.bounds.height + 2)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: -2, y: sv.bounds.height)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: -2, y: -2)))
|
||||
}
|
||||
// Bottom
|
||||
do {
|
||||
sv.position = .bottom
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: 0, y: 0)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width / 2, y: 0)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width / 2, y: -2)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: -2, y: 0)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: -2, y: -2)))
|
||||
}
|
||||
// Left
|
||||
do {
|
||||
sv.position = .left
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width, y: 0)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width, y: sv.bounds.height / 2)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: sv.bounds.width + 2, y: sv.bounds.height / 2)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: sv.bounds.width, y: -2)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: -2, y: -2)))
|
||||
}
|
||||
// Right
|
||||
do {
|
||||
sv.position = .right
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: 0, y: 0)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: 0, y: sv.bounds.height / 2)))
|
||||
XCTAssertTrue(sv.grabberAreaContains(.init(x: -2, y: sv.bounds.height / 2)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: 0, y: -2)))
|
||||
XCTAssertFalse(sv.grabberAreaContains(.init(x: -2, y: -2)))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,3 +77,25 @@ class FloatingPanelProjectableBehavior: FloatingPanelBehavior {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class MockTransitionCoordinator: NSObject, UIViewControllerTransitionCoordinator {
|
||||
func animate(alongsideTransition animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?, completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil) -> Bool { true }
|
||||
func animateAlongsideTransition(in view: UIView?, animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?, completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil) -> Bool { true }
|
||||
func notifyWhenInteractionEnds(_ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void) {}
|
||||
func notifyWhenInteractionChanges(_ handler: @escaping (UIViewControllerTransitionCoordinatorContext) -> Void) {}
|
||||
var isAnimated: Bool = false
|
||||
var presentationStyle: UIModalPresentationStyle = .fullScreen
|
||||
var initiallyInteractive: Bool = false
|
||||
var isInterruptible: Bool = false
|
||||
var isInteractive: Bool = false
|
||||
var isCancelled: Bool = false
|
||||
var transitionDuration: TimeInterval = 0.25
|
||||
var percentComplete: CGFloat = 0
|
||||
var completionVelocity: CGFloat = 0
|
||||
var completionCurve: UIView.AnimationCurve = .easeInOut
|
||||
func viewController(forKey key: UITransitionContextViewControllerKey) -> UIViewController? { nil }
|
||||
func view(forKey key: UITransitionContextViewKey) -> UIView? { nil }
|
||||
var containerView: UIView { UIView() }
|
||||
var targetTransform: CGAffineTransform = .identity
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.
|
||||
|
||||
import UIKit
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
let rootVC = UIViewController(nibName: nil, bundle: nil)
|
||||
rootVC.view.backgroundColor = .gray
|
||||
|
||||
let window = UIWindow()
|
||||
window.rootViewController = rootVC
|
||||
window.makeKeyAndVisible()
|
||||
self.window = window
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Copyright © 2019 scenee. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
|
||||
<rect key="frame" x="0.0" y="626.5" width="375" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="TestingApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
|
||||
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
|
||||
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
|
||||
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
|
||||
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
|
||||
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
|
||||
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
Reference in New Issue
Block a user