Compare commits

..

34 Commits

Author SHA1 Message Date
Shin Yamamoto a917d6a626 Version 2.6.3 2023-07-01 13:54:25 +09:00
Sören Gade 7511ce577d Fix scrollview content staying non-interactive after slowly swiping down (#597)
This was noticed when updating contained SwiftUI views rapidly.

This change is what fixed a certain bug the scroll content can be locked at a negative offset. It was most obvious when the whitespace was large, hence the offset was something around -100.0. At the same time, the contents (like buttons) were non-interactive.

Co-authored-by: Sören Gade <soeren.gade@lichtblick.de>
2023-07-01 11:52:38 +09:00
Shin Yamamoto e7d0a72440 Fix an issue where dismissalTapGestureRecognizer doesn't work in one case (#590)
`dismissalTapGestureRecognizer` didn't work when the panel is added into UIWindow directly as its subview. This PR fixes this issue and also adds the use case in Samples.app.
2023-07-01 11:49:36 +09:00
Shin Yamamoto 44923ef66e [Revised] Fix an issue scrolling jumps with a small scroll view content (#524)
This is the revised version of commit 448fc5c.

Commit 448fc5c has a critical regression in scroll tracking that can cause the
scroll content to bounce after moving a panel, for example, pulling down it from
full to half state.

By re-investigating #524, I found that this problem only occurred with the
`fitToBounds` content mode and a small scroll view content.

Therefore I fixed it in the more specific way.
2023-07-01 11:46:23 +09:00
Shin Yamamoto 2760bc7298 Modify a private typealias name 2023-06-21 21:04:28 +09:00
Shin Yamamoto d428e96b03 Add the SPI manifest YAML file 2023-06-12 20:32:04 +09:00
Shin Yamamoto 67495961e5 Remove unnecessary prints in unit testing 2023-06-11 21:59:29 +09:00
Shin Yamamoto 7b88703e43 ci: add Xcode 14.3 / Swift 5.8 build 2023-06-10 10:01:46 +09:00
Shin Yamamoto c40e66ef3d Fix a trivial bug on Samples app 2023-06-06 11:35:49 +09:00
Shin Yamamoto 53fb131d0e Update the swizzling way in FloatingPanelController 2023-06-03 12:26:57 +09:00
Shin Yamamoto 37969f6cb3 Merge pull request #588 from scenee/release/2.6.2
Release v2.6.2
2023-06-03 10:40:57 +09:00
Shin Yamamoto a0ba3af012 Version 2.6.2 2023-06-03 10:23:03 +09:00
Shin Yamamoto 6082dba6a7 ci: add circleci config for testing on ios13/14 2023-06-03 10:12:13 +09:00
Shin Yamamoto 43327e8123 ci: add timeout-minutes 2023-06-03 10:12:13 +09:00
Shin Yamamoto 0a5bc19d0f Remove the host app for the unit testing 2023-06-03 10:12:13 +09:00
Shin Yamamoto dd52e1eaee Revise an illegible variable name 2023-04-16 10:14:54 +09:00
Shin Yamamoto 22aa055843 Revise the short descriptions 2023-04-16 10:09:39 +09:00
Shin Yamamoto 448fc5cbb4 Stop changing UIScrollView.bounces when locking or unlocking a scroll view (#584)
UIScrollView would unexpectedly change its scroll offset after updating the bounces property when dealing with small scrollable content. This fixes issue #524, "Scrolling jumps when tableView content is small".
2023-04-08 10:30:11 +09:00
Shin Yamamoto b4fe3b408c Remove unused testing targets in the Samples project 2023-04-08 10:11:41 +09:00
Shin Yamamoto 6ecc7924ba Update badges in README 2023-04-06 21:50:49 +09:00
Shin Yamamoto 0b82902233 Update README for the API documentation on GitHub Pages 2023-03-25 11:57:24 +09:00
Shin Yamamoto 597dbd4145 Revise some sentences in README 2023-03-25 11:04:55 +09:00
Shin Yamamoto 1ee949ff1b Merge pull request #583 from scenee/release/2.6.1
Release 2.6.1
2023-03-04 10:46:11 +09:00
Shin Yamamoto 2a29cb5b3e Version 2.6.1 2023-03-04 09:43:23 +09:00
Shin Yamamoto 208ab665da ci: add Maps-SwiftUI example build 2023-03-04 09:42:40 +09:00
Shin Yamamoto 3e20314cfa Update DebugTableViewController with followScrollViewBouncing() API 2023-03-02 21:53:24 +09:00
Shin Yamamoto 5b8e9a54d9 Update trackingScrollViewDidScroll() with doc comments 2023-03-02 21:53:24 +09:00
Vlad d3c30b35d9 track scroll view bouncing (#525) 2023-02-25 11:11:50 +09:00
Shin Yamamoto 8bb3795931 Take care of an invalid bounding rectangle of PassthroughView in a screen rotation 2023-02-25 10:51:19 +09:00
Shin Yamamoto 9383cd001d ci: replace iOS 15 envs on testing
Because testing on iOS 15.4 is buggy.
2023-02-18 12:15:26 +09:00
Shin Yamamoto 6d5f770066 ci: replace macos-10.15 with macos-11
macos-10.15 will be completely removed by 2023-03-31.
https://github.com/actions/runner-images/issues/5583#issuecomment-1426004850
2023-02-18 11:54:19 +09:00
Shin Yamamoto ce2cafed5b Workaround: fix a laggy animation in Samples app
The AutoLayout rendering engine has been changed since iOS 16.
As a result, "Show Detail Panel" in Samples.apps has a laggy animation
when pulling it down to the bottom of the screen. The issue hadn't
occurred until iOS 15. "On Safe Area View" causes this issue. I could
fix it by removing the constraint of its view to the top of the safe area.

As a workaround, I've replaced its top constraint with one of a
constraint to the top of the superview.
2023-02-18 11:46:41 +09:00
Shin Yamamoto 68352218ac ci: upgrade actions/checkout to suppress Node.js 12 warnings 2023-02-18 11:10:35 +09:00
Shin Yamamoto e3736e4214 Merge pull request #582 from scenee/release/2.6.0
Release 2.6.0
2023-02-18 11:06:19 +09:00
24 changed files with 233 additions and 712 deletions
+21
View File
@@ -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
+16 -30
View File
@@ -17,11 +17,14 @@ jobs:
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.3.1"
xcode: "13.4.1"
runsOn: macos-12
- swift: "5.5"
xcode: "13.2.1"
@@ -31,15 +34,12 @@ jobs:
runsOn: macos-11
- swift: "5.3"
xcode: "12.4"
runsOn: macos-10.15
runsOn: macos-11
- swift: "5.2"
xcode: "11.7"
runsOn: macos-10.15
- swift: "5.1"
xcode: "11.3.1"
runsOn: macos-10.15
runsOn: macos-11
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Building in Swift ${{ matrix.swift }}
run: xcodebuild -scheme FloatingPanel SWIFT_VERSION=${{ matrix.swift }} clean build
@@ -55,30 +55,15 @@ jobs:
xcode: "14.1"
sim: "iPhone 14 Pro"
runsOn: macos-12
- os: "15.4"
xcode: "13.3.1"
- os: "15.5"
xcode: "13.4.1"
sim: "iPhone 13 Pro"
runsOn: macos-12
- os: "15.2"
xcode: "13.2.1"
sim: "iPhone 13 Pro"
runsOn: macos-11
- os: "14.5"
xcode: "12.5.1"
sim: "iPhone 12 Pro"
runsOn: macos-11
- os: "14.4"
xcode: "12.4"
sim: "iPhone 12 Pro"
runsOn: macos-10.15
- os: "13.7"
xcode: "11.7"
sim: "iPhone 11 Pro"
runsOn: macos-10.15
steps:
- uses: actions/checkout@v2
- 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-12
@@ -89,10 +74,11 @@ jobs:
matrix:
include:
- example: "Maps"
- example: "Maps-SwiftUI"
- example: "Stocks"
- example: "Samples"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Building ${{ matrix.example }}
run: xcodebuild -workspace FloatingPanel.xcworkspace -scheme ${{ matrix.example }} -sdk iphonesimulator clean build
@@ -111,21 +97,21 @@ jobs:
- target: "x86_64-apple-ios16.1-simulator"
- target: "arm64-apple-ios16.1-simulator"
steps:
- uses: actions/checkout@v2
- 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
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Carthage build"
run: carthage build --use-xcframeworks --no-skip-current
cocoapods:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "CocoaPods: pod lib lint"
run: pod lib lint --allow-warnings
- name: "CocoaPods: pod spec lint"
+5
View File
@@ -0,0 +1,5 @@
version: 1
builder:
configs:
- documentation_targets: [FloatingPanel]
platform: ios
@@ -24,8 +24,6 @@
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 */; };
@@ -37,23 +35,6 @@
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;
@@ -88,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; };
@@ -114,20 +89,6 @@
);
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 */
@@ -154,8 +115,6 @@
children = (
549D23CA233C7779008EF4D7 /* FloatingPanel.framework */,
545DB9EC21511E6300CA77B8 /* Sources */,
545DBA0121511E6400CA77B8 /* Tests */,
545DBA0C21511E6400CA77B8 /* UITests */,
545DB9EB21511E6300CA77B8 /* Products */,
5D82A6AB28D18438006A44BA /* Frameworks */,
);
@@ -165,8 +124,6 @@
isa = PBXGroup;
children = (
545DB9EA21511E6300CA77B8 /* Samples.app */,
545DB9FE21511E6400CA77B8 /* SamplesTests.xctest */,
545DBA0921511E6400CA77B8 /* SamplesUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -190,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 = (
@@ -247,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 */
@@ -296,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" */;
@@ -320,8 +215,6 @@
projectRoot = "";
targets = (
545DB9E921511E6300CA77B8 /* Samples */,
545DB9FD21511E6400CA77B8 /* SamplesTests */,
545DBA0821511E6400CA77B8 /* SamplesUITests */,
);
};
/* End PBXProject section */
@@ -337,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 */
@@ -381,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;
@@ -596,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 */
@@ -701,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 */;
@@ -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"/>
<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">
@@ -598,7 +598,7 @@
</constraints>
</view>
<view alpha="0.5" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Kva-Z7-0qY" customClass="OnSafeAreaView" customModule="Samples" customModuleProvider="target">
<rect key="frame" x="0.0" y="48" width="375" height="730"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="778"/>
<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">
@@ -660,9 +660,9 @@
<color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<constraints>
<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" 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"/>
@@ -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)
}
@@ -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"
@@ -65,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))
@@ -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()
-22
View File
@@ -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>
-28
View File
@@ -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.
}
}
}
-22
View File
@@ -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 its 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.
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "FloatingPanel"
s.version = "2.6.0"
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.
+3 -142
View File
@@ -17,8 +17,6 @@
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 */; };
@@ -45,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 */
@@ -68,9 +59,6 @@
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>"; };
@@ -86,7 +74,6 @@
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 */
@@ -107,13 +94,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
54E740C7218AFD67005C1A34 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -132,7 +112,6 @@
children = (
545DB9C12151169500CA77B8 /* FloatingPanel.framework */,
545DB9CA2151169500CA77B8 /* FloatingPanelTests.xctest */,
54E740CA218AFD67005C1A34 /* FloatingPanelTesting.app */,
);
name = Products;
sourceTree = "<group>";
@@ -165,7 +144,6 @@
545DB9CE2151169500CA77B8 /* Tests */ = {
isa = PBXGroup;
children = (
5469F49E24B003EF00537F8A /* TestingApp */,
54A6B6B022968B530077F348 /* CoreTests.swift */,
545DB9CF2151169500CA77B8 /* ControllerTests.swift */,
542753C522C49A6E00D17955 /* LayoutTests.swift */,
@@ -178,16 +156,6 @@
path = Tests;
sourceTree = "<group>";
};
5469F49E24B003EF00537F8A /* TestingApp */ = {
isa = PBXGroup;
children = (
5469F49F24B003EF00537F8A /* LaunchScreen.storyboard */,
5469F4A024B003EF00537F8A /* AppDelegate.swift */,
5469F4A124B003EF00537F8A /* Info.plist */,
);
path = TestingApp;
sourceTree = "<group>";
};
5D82A6B328D18460006A44BA /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -240,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 */
@@ -280,10 +230,6 @@
};
545DB9C92151169500CA77B8 = {
CreatedOnToolsVersion = 10.0;
TestTargetID = 54E740C9218AFD67005C1A34;
};
54E740C9218AFD67005C1A34 = {
CreatedOnToolsVersion = 10.1;
};
};
};
@@ -302,7 +248,6 @@
targets = (
545DB9C02151169500CA77B8 /* FloatingPanel */,
545DB9C92151169500CA77B8 /* FloatingPanelTests */,
54E740C9218AFD67005C1A34 /* TestingApp */,
);
};
/* End PBXProject section */
@@ -322,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 */
@@ -370,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 */
@@ -386,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 */
@@ -593,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;
};
@@ -614,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;
};
@@ -767,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;
};
@@ -822,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 */;
+13 -13
View File
@@ -1,15 +1,15 @@
[![Build Status](https://travis-ci.org/SCENEE/FloatingPanel.svg?branch=master)](https://travis-ci.org/SCENEE/FloatingPanel)
[![Version](https://img.shields.io/cocoapods/v/FloatingPanel.svg)](https://cocoapods.org/pods/FloatingPanel)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Swift 5](https://img.shields.io/badge/swift-5-orange.svg?style=flat)](https://swift.org/)
[![Platform](https://img.shields.io/cocoapods/p/FloatingPanel.svg)](https://cocoapods.org/pods/FloatingPanel)
[![Swift 5](https://img.shields.io/badge/Swift-5-orange.svg?style=flat)](https://swift.org/)
[![Version](https://img.shields.io/cocoapods/v/FloatingPanel.svg)](https://cocoapods.org/pods/FloatingPanel)
![GitHub Workflow Status (with branch)](https://img.shields.io/github/actions/workflow/status/scenee/FloatingPanel/ci.yml?branch=master)
[![Carthage compatible](https://img.shields.io/badge/carthage-compatible-4BC51D.svg?style=flat)](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.
![Maps](https://github.com/SCENEE/FloatingPanel/blob/master/assets/maps.gif)
![Stocks](https://github.com/SCENEE/FloatingPanel/blob/master/assets/stocks.gif)
@@ -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
+39 -17
View File
@@ -414,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)
}
}
}
@@ -441,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 {
@@ -588,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.
///
@@ -676,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)
}
@@ -709,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)
}
@@ -717,6 +739,6 @@ public extension UIViewController {
}
// For other view controllers
self.fp_original_dismiss(animated: flag, completion: completion)
dismissImp(self, sel, flag, completion)
}
}
+55 -10
View File
@@ -388,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)
@@ -400,7 +400,7 @@ 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 {
@@ -459,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()
@@ -467,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) {
@@ -930,6 +930,8 @@ class Core: NSObject, UIGestureRecognizerDelegate {
""")
if finished, state == layoutAdapter.mostExpandedState, abs(layoutAdapter.offsetFromMostExpandedAnchor) <= 1.0 {
unlockScrollView()
} else if finished, shouldLooselyLockScrollView {
unlockScrollView()
}
}
@@ -937,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:
@@ -1008,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 {
@@ -1017,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
}
@@ -1029,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)
}
+4 -3
View File
@@ -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
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.6.0</string>
<string>2.6.3</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
+5 -2
View File
@@ -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)
-1
View File
@@ -464,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() {
-19
View File
@@ -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
}
}
-43
View File
@@ -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>
-48
View File
@@ -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>