├── Aquaman-Demo ├── en.lproj │ └── LaunchScreen.strings ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── TheFlashViewController.swift ├── Info.plist ├── HeaderView.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── ViewController.swift ├── WonderWomanViewController.swift ├── AppDelegate.swift ├── BatmanViewController.swift ├── SupermanViewController.swift ├── PageViewController.swift └── Main.storyboard ├── demo.gif ├── Aquaman ├── .DS_Store ├── Aquaman.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Aquaman.xcscheme │ └── project.pbxproj └── Aquaman │ ├── Info.plist │ ├── AquamanChildViewController.swift │ ├── Aquaman.h │ ├── AquamanContainView.swift │ ├── UIViewController+Additional.swift │ ├── NSCache+Additional.swift │ ├── UIScrollView+Additional.swift │ ├── AquaMainScrollView.swift │ ├── AquamanProtocol.swift │ ├── AquamanPageViewController+Additional.swift │ └── AquamanPageViewController.swift ├── Tests ├── LinuxMain.swift └── AquamanTests │ ├── XCTestManifests.swift │ └── AquamanTests.swift ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── Aquaman-Demo.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcshareddata │ └── xcschemes │ │ └── Aquaman-Demo.xcscheme └── project.pbxproj ├── Aquaman.xcworkspace ├── xcshareddata │ ├── WorkspaceSettings.xcsettings │ ├── IDEWorkspaceChecks.plist │ └── swiftpm │ │ └── Package.resolved └── contents.xcworkspacedata ├── Podfile ├── Podfile.lock ├── Package.swift ├── Aquaman.podspec ├── Aquaman-DemoUITests ├── Info.plist └── Aquaman_DemoUITests.swift ├── LICENSE ├── .gitignore ├── README-EN.md └── README.md /Aquaman-Demo/en.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bawn/Aquaman/HEAD/demo.gif -------------------------------------------------------------------------------- /Aquaman/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bawn/Aquaman/HEAD/Aquaman/.DS_Store -------------------------------------------------------------------------------- /Aquaman-Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import AquamanTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += AquamanTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Aquaman-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/AquamanTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(AquamanTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Aquaman/Aquaman.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Aquaman.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Aquaman.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Aquaman.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Aquaman-Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Aquaman/Aquaman.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '9.0' 3 | inhibit_all_warnings! 4 | workspace 'Aquaman' 5 | 6 | target 'Aquaman-Demo' do 7 | project './Aquaman-Demo' 8 | use_frameworks! 9 | 10 | pod 'SnapKit', '4.2.0' 11 | pod 'MJRefresh' 12 | # pod 'Trident' 13 | # pod 'Reveal-SDK', '22', :configurations => ['Debug'] 14 | # Pods for Aquaman-Demo 15 | 16 | end 17 | -------------------------------------------------------------------------------- /Aquaman-Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Aquaman", 6 | "repositoryURL": "https://github.com/bugkingK/Aquaman", 7 | "state": { 8 | "branch": null, 9 | "revision": "40080956650a1aa783093f11cfb15f781d6ca432", 10 | "version": "0.1.2" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MJRefresh (3.5.0) 3 | - SnapKit (4.2.0) 4 | 5 | DEPENDENCIES: 6 | - MJRefresh 7 | - SnapKit (= 4.2.0) 8 | 9 | SPEC REPOS: 10 | https://cdn.cocoapods.org/: 11 | - MJRefresh 12 | - SnapKit 13 | 14 | SPEC CHECKSUMS: 15 | MJRefresh: 6afc955813966afb08305477dd7a0d9ad5e79a16 16 | SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a 17 | 18 | PODFILE CHECKSUM: 6ecab50b368fd719f75735e4d61e03b42a41166e 19 | 20 | COCOAPODS: 1.9.3 21 | -------------------------------------------------------------------------------- /Tests/AquamanTests/AquamanTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Aquaman 3 | 4 | final class AquamanTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | XCTAssertEqual(Aquaman().text, "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Aquaman", 8 | platforms: [.iOS(.v9)], 9 | products: [ 10 | .library( 11 | name: "Aquaman", 12 | targets: ["Aquaman"]), 13 | ], 14 | targets: [ 15 | .target( 16 | name: "Aquaman", 17 | path: "./Aquaman/Aquaman") 18 | ] 19 | ) 20 | -------------------------------------------------------------------------------- /Aquaman-Demo/TheFlashViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TheFlashViewController.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2019/9/5. 6 | // Copyright © 2019 bawn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Aquaman 11 | 12 | class TheFlashViewController: UIViewController, AquamanChildViewController { 13 | 14 | @IBOutlet weak var scrollView: UIScrollView! 15 | 16 | func aquamanChildScrollView() -> UIScrollView { 17 | return scrollView 18 | } 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | scrollView.contentInset = UIEdgeInsets(top: 12, left: 0, bottom: 0, right: 0) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Aquaman.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "Aquaman" 4 | s.version = "0.1.2" 5 | s.summary = "An easy solution to nested scrolling" 6 | s.homepage = "https://github.com/bawn/Aquaman" 7 | s.license = { :type => "MIT", :file => "LICENSE" } 8 | s.authors = { "bawn" => "lc5491137@gmail.com" } 9 | s.swift_version = "4.2" 10 | s.source = { :git => "https://github.com/bawn/Aquaman.git", :tag => s.version.to_s } 11 | s.platform = :ios, '9.0' 12 | s.requires_arc = true 13 | s.public_header_files = "Aquaman/Aquaman/Aquaman.h" 14 | s.source_files = ["Aquaman/Aquaman/*.swift", "Aquaman/Aquaman/Aquaman.h"] 15 | end -------------------------------------------------------------------------------- /Aquaman.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Aquaman", 6 | "repositoryURL": "https://github.com/bawn/Aquaman.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "f97de875fac31cabfcd8125047069b40665aa160", 10 | "version": "0.1.3" 11 | } 12 | }, 13 | { 14 | "package": "Trident", 15 | "repositoryURL": "https://github.com/bawn/Trident.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "2eed75e69815da6fc28b05c91cd642bca1c40610", 19 | "version": "0.7.0" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } 26 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Aquaman-DemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Bawn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/AquamanChildViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AquamanChildViewController.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2019/1/7. 6 | // Copyright © 2019 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | public protocol AquamanChildViewController where Self: UIViewController { 30 | func aquamanChildScrollView() -> UIScrollView 31 | } 32 | -------------------------------------------------------------------------------- /Aquaman-DemoUITests/Aquaman_DemoUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Aquaman_DemoUITests.swift 3 | // Aquaman-DemoUITests 4 | // 5 | // Created by bawn on 2019/12/27. 6 | // Copyright © 2019 bawn. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class Aquaman_DemoUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // 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. 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testExample() { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use recording to get started writing UI tests. 32 | // Use XCTAssert and related functions to verify your tests produce the correct results. 33 | } 34 | 35 | func testLaunchPerformance() { 36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 37 | // This measures how long it takes to launch your application. 38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 39 | XCUIApplication().launch() 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Aquaman-Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Aquaman-Demo/HeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeaderView.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2018/12/26. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | class HeaderView: UIView { 29 | 30 | override init(frame: CGRect) { 31 | super.init(frame: frame) 32 | backgroundColor = .cyan 33 | } 34 | 35 | required init?(coder aDecoder: NSCoder) { 36 | super.init(coder: aDecoder) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/Aquaman.h: -------------------------------------------------------------------------------- 1 | // 2 | // Aquaman.h 3 | // Aquaman 4 | // 5 | // Created by bawn on 2019/1/7. 6 | // Copyright © 2019 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | //! Project version number for Aquaman. 29 | FOUNDATION_EXPORT double AquamanVersionNumber; 30 | 31 | //! Project version string for Aquaman. 32 | FOUNDATION_EXPORT const unsigned char AquamanVersionString[]; 33 | 34 | // In this header, you should import all the public headers of your framework using statements like #import 35 | 36 | 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | *.xcuserstate 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | # Package.pins 41 | # Package.resolved 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots/**/*.png 69 | fastlane/test_output 70 | .DS_Store 71 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/AquamanContainView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AquamanContainView.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/12. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | class AquamanContainView: UIView { 29 | weak var viewController: (UIViewController & AquamanChildViewController)? 30 | var isEmpty: Bool { 31 | return subviews.isEmpty 32 | } 33 | 34 | func displayingIn(view: UIView, containView: UIView) -> Bool { 35 | let convertedFrame = containView.convert(frame, to: view) 36 | return view.frame.intersects(convertedFrame) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Aquaman-Demo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/UIViewController+Additional.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+Additional.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/12. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | extension UIViewController { 30 | 31 | public var amPageViewContoller: AquamanPageViewController? { 32 | return parent as? AquamanPageViewController 33 | } 34 | 35 | func clearFromParent() { 36 | willMove(toParent: nil) 37 | beginAppearanceTransition(false, animated: false) 38 | view.removeFromSuperview() 39 | endAppearanceTransition() 40 | removeFromParent() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/NSCache+Additional.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSCache+Additional.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/12. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | extension NSCache where KeyType == NSString, ObjectType == UIViewController { 30 | 31 | subscript(index: Int) -> UIViewController? { 32 | get { 33 | return object(forKey: "\(index)" as NSString) 34 | } 35 | set { 36 | guard let newValue = newValue 37 | , self[index] != newValue else { 38 | return 39 | } 40 | setObject(newValue, forKey: "\(index)" as NSString) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Aquaman-Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Aquaman-Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2019/1/11. 6 | // Copyright © 2019 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | class ViewController: UITableViewController { 29 | 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | } 33 | 34 | override func viewWillAppear(_ animated: Bool) { 35 | super.viewWillAppear(animated) 36 | navigationController?.setNavigationBarHidden(false, animated: animated) 37 | } 38 | 39 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 40 | guard let pageViewController = segue.destination as? PageViewController 41 | , let cell = sender as? UITableViewCell 42 | , let indexPath = tableView.indexPath(for: cell) else { 43 | return 44 | } 45 | pageViewController.indexPath = indexPath 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/UIScrollView+Additional.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+Additional.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/12. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | 30 | private struct AssociatedKeys { 31 | static var AMIsCanScroll = "AMIsCanScroll" 32 | static var AMOriginOffset = "AMOriginOffset" 33 | } 34 | 35 | extension UIScrollView { 36 | internal var am_isCanScroll: Bool { 37 | get { 38 | return (objc_getAssociatedObject(self, &AssociatedKeys.AMIsCanScroll) as? Bool) ?? false 39 | } 40 | set { 41 | objc_setAssociatedObject(self, &AssociatedKeys.AMIsCanScroll, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 42 | } 43 | } 44 | 45 | internal var am_originOffset: CGPoint? { 46 | get { 47 | return objc_getAssociatedObject(self, &AssociatedKeys.AMOriginOffset) as? CGPoint 48 | } 49 | set { 50 | guard am_originOffset == nil else { 51 | return 52 | } 53 | objc_setAssociatedObject(self, &AssociatedKeys.AMOriginOffset, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Aquaman-Demo/WonderWomanViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WonderWomanViewController.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2018/12/10. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | import Aquaman 28 | 29 | class WonderWomanViewController: UIViewController, AquamanChildViewController { 30 | 31 | @IBOutlet weak var tableView: UITableView! 32 | override func viewDidLoad() { 33 | super.viewDidLoad() 34 | } 35 | 36 | func aquamanChildScrollView() -> UIScrollView { 37 | return tableView 38 | } 39 | } 40 | 41 | extension WonderWomanViewController: UITableViewDelegate, UITableViewDataSource { 42 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 43 | return 40 44 | } 45 | 46 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 47 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 48 | cell.textLabel?.text = "\(type(of: self))" + "-" + "\(indexPath.row)" 49 | return cell 50 | } 51 | 52 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 53 | navigationController?.popViewController(animated: true) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/AquaMainScrollView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AquaScrollView.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/7. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | public class AquaMainScrollView: UIScrollView, UIGestureRecognizerDelegate { 29 | var headerViewHeight: CGFloat = 0.0 30 | var menuViewHeight: CGFloat = 0.0 31 | 32 | public override init(frame: CGRect) { 33 | super.init(frame: .zero) 34 | scrollsToTop = true 35 | backgroundColor = .white 36 | showsHorizontalScrollIndicator = false 37 | showsVerticalScrollIndicator = false 38 | translatesAutoresizingMaskIntoConstraints = false 39 | } 40 | 41 | required init?(coder: NSCoder) { 42 | super.init(coder: coder) 43 | } 44 | 45 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 46 | 47 | guard let scrollView = gestureRecognizer.view as? UIScrollView else { 48 | return false 49 | } 50 | 51 | let offsetY = headerViewHeight + menuViewHeight 52 | let contentSize = scrollView.contentSize 53 | let targetRect = CGRect(x: 0, 54 | y: offsetY - UIApplication.shared.statusBarFrame.height, 55 | width: contentSize.width, 56 | height: contentSize.height - offsetY) 57 | 58 | let currentPoint = gestureRecognizer.location(in: self) 59 | return targetRect.contains(currentPoint) 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /Aquaman/Aquaman.xcodeproj/xcshareddata/xcschemes/Aquaman.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Aquaman-Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2019/1/7. 6 | // Copyright © 2019 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | @UIApplicationMain 29 | class AppDelegate: UIResponder, UIApplicationDelegate { 30 | 31 | var window: UIWindow? 32 | 33 | 34 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 35 | // Override point for customization after application launch. 36 | return true 37 | } 38 | 39 | func applicationWillResignActive(_ application: UIApplication) { 40 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 41 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 42 | } 43 | 44 | func applicationDidEnterBackground(_ application: UIApplication) { 45 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 47 | } 48 | 49 | func applicationWillEnterForeground(_ application: UIApplication) { 50 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 51 | } 52 | 53 | func applicationDidBecomeActive(_ application: UIApplication) { 54 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 55 | } 56 | 57 | func applicationWillTerminate(_ application: UIApplication) { 58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 59 | } 60 | 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /Aquaman-Demo/BatmanViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BatmanViewController.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2018/12/28. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | import Aquaman 28 | 29 | class BatmanViewController: UIViewController, AquamanChildViewController { 30 | @IBOutlet weak var collectionView: UICollectionView! 31 | 32 | override func viewDidLoad() { 33 | super.viewDidLoad() 34 | 35 | collectionView.alwaysBounceVertical = true 36 | } 37 | 38 | func aquamanChildScrollView() -> UIScrollView { 39 | return collectionView 40 | } 41 | 42 | } 43 | 44 | extension BatmanViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { 45 | 46 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 47 | return 4 48 | } 49 | 50 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 51 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) 52 | return cell 53 | } 54 | 55 | 56 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 57 | return 12 58 | } 59 | 60 | 61 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 62 | return 12 63 | } 64 | 65 | 66 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 67 | return UIEdgeInsets(top: 24, left: 12, bottom: 12, right: 12) 68 | } 69 | 70 | 71 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 72 | let width = floor((collectionView.bounds.width - 12.0 * 3.0) * 0.5) 73 | return CGSize(width: width, height: width) 74 | } 75 | 76 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 77 | navigationController?.popViewController(animated: true) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Aquaman-Demo/SupermanViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SupermanViewController.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2018/12/8. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | import Aquaman 28 | 29 | class SupermanViewController: UIViewController, AquamanChildViewController { 30 | @IBOutlet weak var tableView: UITableView! 31 | 32 | override func viewDidLoad() { 33 | super.viewDidLoad() 34 | 35 | tableView.contentInset = UIEdgeInsets(top: 12, left: 0, bottom: 12, right: 0) 36 | } 37 | 38 | func aquamanChildScrollView() -> UIScrollView { 39 | return tableView 40 | } 41 | } 42 | 43 | 44 | extension SupermanViewController: UITableViewDelegate, UITableViewDataSource { 45 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 46 | return 20 47 | } 48 | 49 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 50 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 51 | if indexPath.row == 0 { 52 | cell.textLabel?.text = "Update head view height" 53 | } else if indexPath.row == 1 { 54 | cell.textLabel?.text = "Set select" 55 | } else { 56 | cell.textLabel?.text = "Title" 57 | } 58 | return cell 59 | } 60 | 61 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 62 | tableView.deselectRow(at: indexPath, animated: true) 63 | 64 | guard let pageViewController = parent as? PageViewController else { 65 | return 66 | } 67 | 68 | if indexPath.row == 0 { 69 | 70 | tableView.isUserInteractionEnabled = false 71 | var array = [250, 80, 150, 0] 72 | let headerViewHeight = pageViewController.headerViewHeight 73 | array.removeAll(where: {$0 == Int(headerViewHeight)}) 74 | pageViewController.headerViewHeight = CGFloat(array.randomElement()!) 75 | 76 | pageViewController.updateHeaderViewHeight(animated: true, 77 | duration: 0.25) { (finish) in 78 | tableView.isUserInteractionEnabled = true 79 | } 80 | } else if indexPath.row == 1 { 81 | 82 | pageViewController.setSelect(index: pageViewController.currentIndex + 1, 83 | animation: [true, false].randomElement()!) 84 | } else { 85 | navigationController?.popViewController(animated: true) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Aquaman-Demo.xcodeproj/xcshareddata/xcschemes/Aquaman-Demo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 64 | 70 | 71 | 72 | 73 | 79 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- 1 | # Aquaman 2 | 3 | ![License MIT](https://img.shields.io/dub/l/vibe-d.svg) 4 | ![Pod version](http://img.shields.io/cocoapods/v/Aquaman.svg?style=flat) 5 | ![Platform info](http://img.shields.io/cocoapods/p/LCNetwork.svg?style=flat) 6 | [![Support](https://img.shields.io/badge/support-iOS9.0+-blue.svg?style=flat)](https://www.apple.com/nl/ios/) 7 | [![Swift 4.2](https://camo.githubusercontent.com/cc157628e33009bbb18f6e476955a0f641f407d9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53776966742d342e322d6f72616e67652e7376673f7374796c653d666c6174)](https://developer.apple.com/swift/) 8 | 9 | A pure-Swift library for nested display of horizontal and vertical scrolling views. 10 | 11 | ![demo](./demo.gif) 12 | 13 | ## Requirements 14 | 15 | - iOS 9.0+ 16 | - Swift 4.2+ 17 | - Xcode 10+ 18 | 19 | 20 | 21 | ## Installation 22 | 23 | #### [CocoaPods](http://cocoapods.org/) (recommended) 24 | 25 | ``` 26 | use_frameworks! 27 | 28 | pod 'Aquaman' 29 | ``` 30 | 31 | ## Usage 32 | 33 | First make sure to import the framework: 34 | 35 | ``` 36 | import Aquaman 37 | ``` 38 | 39 | Basically, we just need to provide the list of child view controllers to show. Then call some necessary methods. 40 | 41 | Let's see the steps to do this: 42 | 43 | #### Create a AquamanPageViewController subclass 44 | 45 | ```swift 46 | import Aquaman 47 | 48 | class PageViewController: AquamanPageViewController { 49 | // ... 50 | } 51 | ``` 52 | 53 | #### Provide the view controllers that will appear embedded into the AquamanPageViewController 54 | 55 | ```swift 56 | override func numberOfViewControllers(in pageController: AquamanPageViewController) -> Int { 57 | return count 58 | } 59 | 60 | override func pageController(_ pageController: AquamanPageViewController, viewControllerAt index: Int) -> (UIViewController & AquamanChildViewController) { 61 | // ... 62 | return viewController 63 | } 64 | 65 | ``` 66 | 67 | Every UIViewController that will appear within the AquamanPageViewController should conform to `AquamanChildViewController` by implementing `func aquamanChildScrollView() -> UIScrollView` 68 | 69 | ```swift 70 | import Aquaman 71 | class ChildViewController: UIViewController, AquamanChildViewController { 72 | 73 | @IBOutlet weak var tableView: UITableView! 74 | func aquamanChildScrollView() -> UIScrollView { 75 | return tableView 76 | } 77 | // ... 78 | } 79 | ``` 80 | 81 | 82 | 83 | #### Provide the headerView and headerView height 84 | 85 | ```swift 86 | override func headerViewFor(_ pageController: AquamanPageViewController) -> UIView { 87 | return HeaderView() 88 | } 89 | 90 | override func headerViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 91 | return headerViewHeight 92 | } 93 | ``` 94 | 95 | #### Provide the menuView and menuView height 96 | 97 | ```swift 98 | override func menuViewFor(_ pageController: AquamanPageViewController) -> UIView { 99 | return menuView 100 | } 101 | 102 | override func menuViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 103 | return menuViewHeight 104 | } 105 | ``` 106 | 107 | #### Update menuView's layout when content scroll view did scroll and check state when viewController did end isplay 108 | 109 | ```swift 110 | override func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidScroll scrollView: UIScrollView) { 111 | menuView.updateLayout(scrollView) 112 | } 113 | 114 | override func pageController(_ pageController: AquamanPageViewController, didDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 115 | menuView.checkState(animation: true) 116 | } 117 | ``` 118 | 119 | 120 | 121 | ## Examples 122 | 123 | Follow these 4 steps to run Example project: 124 | 125 | 1. Clone Aquaman repository 126 | 2. Run the `pod install` command 127 | 3. Open Aquaman workspace 128 | 4. Run the Aquaman-Demo project. 129 | 130 | ### License 131 | 132 | Aquaman is released under the MIT license. See LICENSE for details. 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aquaman 2 | 3 | ![License MIT](https://img.shields.io/dub/l/vibe-d.svg) 4 | ![Pod version](http://img.shields.io/cocoapods/v/Aquaman.svg?style=flat) 5 | ![Platform info](http://img.shields.io/cocoapods/p/LCNetwork.svg?style=flat) 6 | [![Support](https://img.shields.io/badge/support-iOS9.0+-blue.svg?style=flat)](https://www.apple.com/nl/ios/) 7 | [![Swift 4.2](https://camo.githubusercontent.com/cc157628e33009bbb18f6e476955a0f641f407d9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53776966742d342e322d6f72616e67652e7376673f7374796c653d666c6174)](https://developer.apple.com/swift/) 8 | 9 | 类似于淘票票首页,抖音、简书个人主页的嵌套滚动库 10 | 11 | ![demo](./demo.gif) 12 | 13 | ## Requirements 14 | 15 | - iOS 9.0+ 16 | - Swift 4.2+ 17 | - Xcode 10+ 18 | 19 | 20 | 21 | ## Installation 22 | 23 | #### [CocoaPods](http://cocoapods.org/) 24 | 25 | ``` 26 | use_frameworks! 27 | 28 | pod 'Aquaman' 29 | ``` 30 | 31 | #### Swift Package Manager 32 | Add the following dependency to your Package.swift manifest: 33 | 34 | ``` 35 | .package(url: "https://github.com/bawn/Aquaman.git", .branch("master")), 36 | ``` 37 | 38 | ## Usage 39 | 40 | [English documentation](https://github.com/bawn/Aquaman/blob/master/README-EN.md) 41 | 42 | 首先需要导入 Aquaman 43 | 44 | ``` 45 | import Aquaman 46 | ``` 47 | 48 | 49 | 50 | #### 创建 AquamanPageViewController 子类 51 | 52 | ```swift 53 | import Aquaman 54 | 55 | class PageViewController: AquamanPageViewController { 56 | // ... 57 | } 58 | ``` 59 | 60 | #### 重写以下协议方法以提供 viewController 和相应的数量 61 | 62 | ```swift 63 | override func numberOfViewControllers(in pageController: AquamanPageViewController) -> Int { 64 | return count 65 | } 66 | 67 | override func pageController(_ pageController: AquamanPageViewController, viewControllerAt index: Int) -> (UIViewController & AquamanChildViewController) { 68 | // ... 69 | return viewController 70 | } 71 | 72 | ``` 73 | 74 | 注意: 所提供的 viewController 必须都遵守 `AquamanChildViewController` 协议,并实现 `func aquamanChildScrollView() -> UIScrollView` 方法 75 | 76 | ```swift 77 | import Aquaman 78 | class ChildViewController: UIViewController, AquamanChildViewController { 79 | 80 | @IBOutlet weak var tableView: UITableView! 81 | func aquamanChildScrollView() -> UIScrollView { 82 | return tableView 83 | } 84 | // ... 85 | } 86 | ``` 87 | 88 | 89 | 90 | #### 重写以下协议方法以提供 headerView 及其高度 91 | 92 | ```swift 93 | override func headerViewFor(_ pageController: AquamanPageViewController) -> UIView { 94 | return HeaderView() 95 | } 96 | 97 | override func headerViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 98 | return headerViewHeight 99 | } 100 | ``` 101 | 102 | #### 重写以下协议方法以提供 menuView 及其高度 103 | 104 | ```swift 105 | override func menuViewFor(_ pageController: AquamanPageViewController) -> UIView { 106 | return menuView 107 | } 108 | 109 | override func menuViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 110 | return menuViewHeight 111 | } 112 | ``` 113 | 114 | Aquaman 采用的是 menuView 和主体功能分离的设计,以满足 menuView 有时候需要深度定制的需求,所以 menuView 需要开发者自己实现,当然这里也提供了现成的 menuView 库:[Trident](https://github.com/bawn/Trident) 115 | 116 | #### 更新 menuView 的布局 117 | 118 | ```swift 119 | override func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidScroll scrollView: UIScrollView) { 120 | menuView.updateLayout(scrollView) 121 | } 122 | 123 | override func pageController(_ pageController: AquamanPageViewController, didDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 124 | menuView.checkState(animation: true) 125 | } 126 | ``` 127 | 128 | 由于 menuView 和 pageController 不存在强关联关系,所以在滚动的时候需要更新 menuView 布局,在显示相应的 viewController 的时候需要检查 menuView 的状态,具体参考 demo 129 | 130 | ## Examples 131 | 132 | Follow these 4 steps to run Example project: 133 | 134 | 1. Clone Aquaman repository 135 | 2. Run the `pod install` command 136 | 3. Open Aquaman workspace 137 | 4. Run the Aquaman-Demo project. 138 | 139 | ### License 140 | 141 | Aquaman is released under the MIT license. See LICENSE for details. 142 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/AquamanProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AquamanProtocol.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/7. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | protocol AMPageControllerDataSource: class { 30 | 31 | func pageController(_ pageController: AquamanPageViewController, viewControllerAt index: Int) -> (UIViewController & AquamanChildViewController) 32 | func numberOfViewControllers(in pageController: AquamanPageViewController) -> Int 33 | func headerViewFor(_ pageController: AquamanPageViewController) -> UIView 34 | func headerViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat 35 | func menuViewFor(_ pageController: AquamanPageViewController) -> UIView 36 | func menuViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat 37 | func menuViewPinHeightFor(_ pageController: AquamanPageViewController) -> CGFloat 38 | 39 | /// The index of the controller displayed by default. You should have menview ready before setting this value 40 | /// 41 | /// - Parameter pageController: AquamanPageViewController 42 | /// - Returns: Int 43 | func originIndexFor(_ pageController: AquamanPageViewController) -> Int 44 | } 45 | 46 | protocol AMPageControllerDelegate: class { 47 | 48 | /// Any offset changes in pageController's mainScrollView 49 | /// 50 | /// - Parameters: 51 | /// - pageController: AquamanPageViewController 52 | /// - scrollView: mainScrollView 53 | func pageController(_ pageController: AquamanPageViewController, mainScrollViewDidScroll scrollView: UIScrollView) 54 | 55 | 56 | /// Method call when contentScrollView did end scroll 57 | /// 58 | /// - Parameters: 59 | /// - pageController: AquamanPageViewController 60 | /// - scrollView: contentScrollView 61 | func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidEndScroll scrollView: UIScrollView) 62 | 63 | 64 | /// Any offset changes in pageController's contentScrollView 65 | /// 66 | /// - Parameters: 67 | /// - pageController: AquamanPageViewController 68 | /// - scrollView: contentScrollView 69 | func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidScroll scrollView: UIScrollView) 70 | 71 | /// Method call when viewController will cache 72 | /// 73 | /// - Parameters: 74 | /// - pageController: AquamanPageViewController 75 | /// - viewController: target viewController 76 | /// - index: target viewController's index 77 | func pageController(_ pageController: AquamanPageViewController, willCache viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) 78 | 79 | 80 | /// Method call when viewController will display 81 | /// 82 | /// - Parameters: 83 | /// - pageController: AquamanPageViewController 84 | /// - viewController: target viewController 85 | /// - index: target viewController's index 86 | func pageController(_ pageController: AquamanPageViewController, willDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) 87 | 88 | 89 | /// Method call when viewController did display 90 | /// 91 | /// - Parameters: 92 | /// - pageController: AquamanPageViewController 93 | /// - viewController: target viewController 94 | /// - index: target viewController's index 95 | func pageController(_ pageController: AquamanPageViewController, didDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) 96 | 97 | 98 | /// Method call when menuView is adsorption 99 | /// 100 | /// - Parameters: 101 | /// - pageController: AquamanPageViewController 102 | /// - isAdsorption: is adsorption 103 | func pageController(_ pageController: AquamanPageViewController, menuView isAdsorption: Bool) 104 | 105 | 106 | /// Asks the delegate for the margins to apply to content. 107 | /// - Parameter pageController: AquamanPageViewController 108 | func contentInsetFor(_ pageController: AquamanPageViewController) -> UIEdgeInsets 109 | 110 | } 111 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/AquamanPageViewController+Additional.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AquamanPageViewController.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/7. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | extension AquamanPageViewController { 30 | public func updateHeaderViewHeight(animated: Bool = false, 31 | duration: TimeInterval = 0.25, 32 | completion: ((Bool) -> Void)? = nil) { 33 | 34 | headerViewHeight = headerViewHeightFor(self) 35 | sillValue = headerViewHeight - menuViewPinHeight 36 | 37 | mainScrollView.headerViewHeight = headerViewHeight 38 | headerViewConstraint?.constant = headerViewHeight 39 | 40 | var manualHandel = false 41 | if mainScrollView.contentOffset.y < sillValue { 42 | currentChildScrollView?.contentOffset = currentChildScrollView?.am_originOffset ?? .zero 43 | currentChildScrollView?.am_isCanScroll = false 44 | mainScrollView.am_isCanScroll = true 45 | manualHandel = true 46 | } else if mainScrollView.contentOffset.y == sillValue { 47 | mainScrollView.am_isCanScroll = false 48 | manualHandel = true 49 | } 50 | let isAdsorption = (headerViewHeight <= 0.0) ? true : !mainScrollView.am_isCanScroll 51 | if animated { 52 | UIView.animate(withDuration: duration, animations: { 53 | self.mainScrollView.layoutIfNeeded() 54 | if manualHandel { 55 | self.pageController(self, menuView: isAdsorption) 56 | } 57 | }) { (finish) in 58 | completion?(finish) 59 | } 60 | } else { 61 | self.pageController(self, menuView: isAdsorption) 62 | completion?(true) 63 | } 64 | } 65 | 66 | public func setSelect(index: Int, animation: Bool) { 67 | let offset = CGPoint(x: contentScrollView.bounds.width * CGFloat(index), 68 | y: contentScrollView.contentOffset.y) 69 | contentScrollView.setContentOffset(offset, animated: animation) 70 | if animation == false { 71 | contentScrollViewDidEndScroll(contentScrollView) 72 | } 73 | } 74 | 75 | public func scrollToTop(_ animation: Bool) { 76 | currentChildScrollView?.setContentOffset(currentChildScrollView?.am_originOffset ?? .zero, animated: true) 77 | mainScrollView.am_isCanScroll = true 78 | mainScrollView.setContentOffset(.zero, animated: animation) 79 | } 80 | 81 | public func reloadData() { 82 | mainScrollView.isUserInteractionEnabled = false 83 | clear() 84 | obtainDataSource() 85 | updateOriginContent() 86 | setupDataSource() 87 | view.layoutIfNeeded() 88 | if originIndex > 0 { 89 | setSelect(index: originIndex, animation: false) 90 | } else { 91 | showChildViewContoller(at: originIndex) 92 | didDisplayViewController(at: originIndex) 93 | } 94 | mainScrollView.isUserInteractionEnabled = true 95 | } 96 | } 97 | 98 | 99 | extension AquamanPageViewController: UIScrollViewDelegate { 100 | 101 | public func scrollViewDidScroll(_ scrollView: UIScrollView) { 102 | 103 | if scrollView == mainScrollView { 104 | pageController(self, mainScrollViewDidScroll: scrollView) 105 | let offsetY = scrollView.contentOffset.y 106 | if offsetY >= sillValue { 107 | scrollView.contentOffset = CGPoint(x: 0, y: sillValue) 108 | currentChildScrollView?.am_isCanScroll = true 109 | scrollView.am_isCanScroll = false 110 | pageController(self, menuView: !scrollView.am_isCanScroll) 111 | } else { 112 | 113 | if scrollView.am_isCanScroll == false { 114 | pageController(self, menuView: true) 115 | scrollView.contentOffset = CGPoint(x: 0, y: sillValue) 116 | } else { 117 | pageController(self, menuView: false) 118 | } 119 | } 120 | } else { 121 | pageController(self, contentScrollViewDidScroll: scrollView) 122 | layoutChildViewControlls() 123 | } 124 | } 125 | 126 | public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { 127 | if scrollView == contentScrollView { 128 | mainScrollView.isScrollEnabled = false 129 | } 130 | } 131 | 132 | 133 | public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { 134 | if scrollView == contentScrollView { 135 | mainScrollView.isScrollEnabled = true 136 | if decelerate == false { 137 | contentScrollViewDidEndScroll(contentScrollView) 138 | } 139 | } 140 | } 141 | 142 | public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 143 | if scrollView == contentScrollView { 144 | contentScrollViewDidEndScroll(contentScrollView) 145 | } 146 | } 147 | 148 | 149 | public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { 150 | if scrollView == contentScrollView { 151 | contentScrollViewDidEndScroll(contentScrollView) 152 | } 153 | } 154 | 155 | public func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { 156 | guard scrollView == mainScrollView else { 157 | return false 158 | } 159 | currentChildScrollView?.setContentOffset(currentChildScrollView?.am_originOffset ?? .zero, animated: true) 160 | return true 161 | } 162 | 163 | } 164 | 165 | extension AquamanPageViewController { 166 | internal func childScrollViewDidScroll(_ scrollView: UIScrollView) { 167 | if scrollView.am_isCanScroll == false { 168 | scrollView.contentOffset = scrollView.am_originOffset ?? .zero 169 | } 170 | let offsetY = scrollView.contentOffset.y 171 | if offsetY <= (scrollView.am_originOffset ?? .zero).y { 172 | scrollView.contentOffset = scrollView.am_originOffset ?? .zero 173 | scrollView.am_isCanScroll = false 174 | mainScrollView.am_isCanScroll = true 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Aquaman-Demo/PageViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PageViewController.swift 3 | // Aquaman-Demo 4 | // 5 | // Created by bawn on 2018/12/8. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | import MJRefresh 28 | import Aquaman 29 | import Trident 30 | 31 | class PageViewController: AquamanPageViewController { 32 | 33 | var indexPath = IndexPath(row: 0, section: 0) 34 | lazy var menuView: TridentMenuView = { 35 | let view = TridentMenuView(parts: 36 | .normalTextColor(UIColor.gray), 37 | .selectedTextColor(UIColor.blue), 38 | .normalTextFont(UIFont.systemFont(ofSize: 15.0)), 39 | .selectedTextFont(UIFont.systemFont(ofSize: 15.0, weight: .medium)), 40 | .switchStyle(.line), 41 | .sliderStyle( 42 | SliderViewStyle(parts: 43 | .backgroundColor(.blue), 44 | .height(3.0), 45 | .cornerRadius(1.5), 46 | .position(.bottom), 47 | .extraWidth(indexPath.row == 0 ? -10.0 : 4.0), 48 | .shape(indexPath.row == 0 ? .line : .triangle) 49 | ) 50 | ), 51 | .bottomLineStyle( 52 | BottomLineViewStyle(parts: 53 | .hidden(indexPath.row == 0 ? false : true) 54 | ) 55 | ) 56 | ) 57 | view.delegate = self 58 | return view 59 | }() 60 | 61 | private let headerView = HeaderView() 62 | private lazy var count = indexPath.row == 0 ? 3 : 0 63 | var headerViewHeight: CGFloat = 200.0 64 | private var menuViewHeight: CGFloat = 54.0 65 | 66 | override func viewDidLoad() { 67 | super.viewDidLoad() 68 | 69 | menuView.contentInset = UIEdgeInsets(top: 0, left: 24, bottom: 0, right: 24) 70 | mainScrollView.mj_header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: #selector(updateData)) 71 | switch indexPath.row { 72 | case 0: 73 | menuView.titles = ["Superman", "Batman", "Wonder Woman"] 74 | case 1: 75 | headerView.isHidden = true 76 | menuView.isHidden = true 77 | mainScrollView.mj_header?.beginRefreshing() 78 | default: 79 | break 80 | } 81 | } 82 | 83 | @objc func updateData() { 84 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { 85 | self.headerView.isHidden = false 86 | self.menuView.isHidden = false 87 | self.menuView.titles = ["Superman", "Batman", "Wonder Woman", "The Flash"] 88 | self.count = self.menuView.titles.count 89 | self.headerViewHeight = 120.0 90 | self.menuViewHeight = 54.0 91 | self.reloadData() 92 | if self.mainScrollView.mj_header?.isRefreshing ?? false { 93 | self.mainScrollView.mj_header?.endRefreshing() 94 | } 95 | } 96 | } 97 | 98 | override func viewWillAppear(_ animated: Bool) { 99 | super.viewWillAppear(animated) 100 | switch indexPath.row { 101 | case 0: 102 | navigationController?.setNavigationBarHidden(true, animated: animated) 103 | default: 104 | break 105 | } 106 | } 107 | 108 | override func headerViewFor(_ pageController: AquamanPageViewController) -> UIView { 109 | return headerView 110 | } 111 | 112 | override func headerViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 113 | return headerViewHeight 114 | } 115 | 116 | override func numberOfViewControllers(in pageController: AquamanPageViewController) -> Int { 117 | return count 118 | } 119 | 120 | override func pageController(_ pageController: AquamanPageViewController, viewControllerAt index: Int) -> (UIViewController & AquamanChildViewController) { 121 | let storyboard = UIStoryboard(name: "Main", bundle: nil) 122 | if index == 0 { 123 | return storyboard.instantiateViewController(withIdentifier: "SupermanViewController") as! SupermanViewController 124 | } else if index == 1 { 125 | return storyboard.instantiateViewController(withIdentifier: "BatmanViewController") as! BatmanViewController 126 | } else if index == 2 { 127 | return storyboard.instantiateViewController(withIdentifier: "WonderWomanViewController") as! WonderWomanViewController 128 | } else { 129 | return storyboard.instantiateViewController(withIdentifier: "TheFlashViewController") as! TheFlashViewController 130 | } 131 | } 132 | 133 | // 默认显示的 ViewController 的 index 134 | override func originIndexFor(_ pageController: AquamanPageViewController) -> Int { 135 | switch indexPath.row { 136 | case 0: 137 | return 0 138 | case 1: 139 | return 1 140 | default: 141 | return 0 142 | } 143 | } 144 | 145 | override func menuViewFor(_ pageController: AquamanPageViewController) -> UIView { 146 | return menuView 147 | } 148 | 149 | override func menuViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 150 | return menuViewHeight 151 | } 152 | 153 | override func menuViewPinHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 154 | return 0.0 155 | } 156 | 157 | 158 | override func pageController(_ pageController: AquamanPageViewController, mainScrollViewDidScroll scrollView: UIScrollView) { 159 | 160 | } 161 | 162 | override func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidScroll scrollView: UIScrollView) { 163 | menuView.updateLayout(scrollView) 164 | } 165 | 166 | override func pageController(_ pageController: AquamanPageViewController, 167 | contentScrollViewDidEndScroll scrollView: UIScrollView) { 168 | 169 | } 170 | 171 | override func pageController(_ pageController: AquamanPageViewController, menuView isAdsorption: Bool) { 172 | menuView.backgroundColor = isAdsorption ? .red : .white 173 | } 174 | 175 | 176 | override func pageController(_ pageController: AquamanPageViewController, willDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 177 | } 178 | 179 | override func pageController(_ pageController: AquamanPageViewController, didDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 180 | menuView.checkState(animation: true) 181 | } 182 | 183 | override func contentInsetFor(_ pageController: AquamanPageViewController) -> UIEdgeInsets { 184 | switch indexPath.row { 185 | case 0: 186 | return UIEdgeInsets(top: -UIApplication.shared.statusBarFrame.height, left: 0, bottom: 0, right: 0) 187 | case 1: 188 | return .zero 189 | default: 190 | return .zero 191 | } 192 | } 193 | } 194 | 195 | 196 | extension PageViewController: TridentMenuViewDelegate { 197 | func menuView(_ menuView: TridentMenuView, didSelectedItemAt index: Int) { 198 | guard index < count else { 199 | return 200 | } 201 | switch indexPath.row { 202 | case 0: 203 | setSelect(index: index, animation: true) 204 | case 1: 205 | setSelect(index: index, animation: false) 206 | default: 207 | break 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /Aquaman/Aquaman.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0748581C6F98F9B286749D5B /* libPods-Aquaman.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 17D7F62C8EA97B4F4AA45B89 /* libPods-Aquaman.a */; }; 11 | DF0DDABC21E35C440086663E /* Aquaman.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0DDABA21E35C440086663E /* Aquaman.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | DF744C3C239F4F1F003A8EB4 /* AquamanProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF744C3B239F4F1F003A8EB4 /* AquamanProtocol.swift */; }; 13 | DF7F9F0C21E37969000F4317 /* UIViewController+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0521E37968000F4317 /* UIViewController+Additional.swift */; }; 14 | DF7F9F0D21E37969000F4317 /* UIScrollView+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0621E37968000F4317 /* UIScrollView+Additional.swift */; }; 15 | DF7F9F0E21E37969000F4317 /* AquamanContainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0721E37968000F4317 /* AquamanContainView.swift */; }; 16 | DF7F9F0F21E37969000F4317 /* AquaMainScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0821E37968000F4317 /* AquaMainScrollView.swift */; }; 17 | DF7F9F1021E37969000F4317 /* AquamanChildViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0921E37968000F4317 /* AquamanChildViewController.swift */; }; 18 | DF7F9F1121E37969000F4317 /* NSCache+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0A21E37968000F4317 /* NSCache+Additional.swift */; }; 19 | DF7F9F1221E37969000F4317 /* AquamanPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F0B21E37968000F4317 /* AquamanPageViewController.swift */; }; 20 | DFFEA09D24A8A5BE0043D896 /* AquamanPageViewController+Additional.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFEA09C24A8A5BE0043D896 /* AquamanPageViewController+Additional.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 17D7F62C8EA97B4F4AA45B89 /* libPods-Aquaman.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Aquaman.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 4E2ADF93CCF5BBBB14110499 /* Pods-Aquaman.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Aquaman.debug.xcconfig"; path = "Target Support Files/Pods-Aquaman/Pods-Aquaman.debug.xcconfig"; sourceTree = ""; }; 26 | 6DFF8C1B0CD3525BDCE645C5 /* Pods-Aquaman.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Aquaman.release.xcconfig"; path = "Target Support Files/Pods-Aquaman/Pods-Aquaman.release.xcconfig"; sourceTree = ""; }; 27 | DF0DDAB721E35C440086663E /* Aquaman.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Aquaman.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | DF0DDABA21E35C440086663E /* Aquaman.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Aquaman.h; sourceTree = ""; }; 29 | DF0DDABB21E35C440086663E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | DF744C3B239F4F1F003A8EB4 /* AquamanProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AquamanProtocol.swift; sourceTree = ""; }; 31 | DF7F9F0521E37968000F4317 /* UIViewController+Additional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Additional.swift"; sourceTree = ""; }; 32 | DF7F9F0621E37968000F4317 /* UIScrollView+Additional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Additional.swift"; sourceTree = ""; }; 33 | DF7F9F0721E37968000F4317 /* AquamanContainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AquamanContainView.swift; sourceTree = ""; }; 34 | DF7F9F0821E37968000F4317 /* AquaMainScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AquaMainScrollView.swift; sourceTree = ""; }; 35 | DF7F9F0921E37968000F4317 /* AquamanChildViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AquamanChildViewController.swift; sourceTree = ""; }; 36 | DF7F9F0A21E37968000F4317 /* NSCache+Additional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSCache+Additional.swift"; sourceTree = ""; }; 37 | DF7F9F0B21E37968000F4317 /* AquamanPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AquamanPageViewController.swift; sourceTree = ""; }; 38 | DFFEA09C24A8A5BE0043D896 /* AquamanPageViewController+Additional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AquamanPageViewController+Additional.swift"; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | DF0DDAB421E35C440086663E /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 0748581C6F98F9B286749D5B /* libPods-Aquaman.a in Frameworks */, 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 514AF2F5FB7701F6EF65FBCA /* Frameworks */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 17D7F62C8EA97B4F4AA45B89 /* libPods-Aquaman.a */, 57 | ); 58 | name = Frameworks; 59 | sourceTree = ""; 60 | }; 61 | 8EE780A59AD49E1E96C3E14B /* Pods */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 4E2ADF93CCF5BBBB14110499 /* Pods-Aquaman.debug.xcconfig */, 65 | 6DFF8C1B0CD3525BDCE645C5 /* Pods-Aquaman.release.xcconfig */, 66 | ); 67 | name = Pods; 68 | path = ../Pods; 69 | sourceTree = ""; 70 | }; 71 | DF0DDAAD21E35C440086663E = { 72 | isa = PBXGroup; 73 | children = ( 74 | DF0DDAB921E35C440086663E /* Aquaman */, 75 | DF0DDAB821E35C440086663E /* Products */, 76 | 8EE780A59AD49E1E96C3E14B /* Pods */, 77 | 514AF2F5FB7701F6EF65FBCA /* Frameworks */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | DF0DDAB821E35C440086663E /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | DF0DDAB721E35C440086663E /* Aquaman.framework */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | DF0DDAB921E35C440086663E /* Aquaman */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | DF0DDABA21E35C440086663E /* Aquaman.h */, 93 | DF744C3B239F4F1F003A8EB4 /* AquamanProtocol.swift */, 94 | DF7F9F0B21E37968000F4317 /* AquamanPageViewController.swift */, 95 | DFFEA09C24A8A5BE0043D896 /* AquamanPageViewController+Additional.swift */, 96 | DF7F9F0921E37968000F4317 /* AquamanChildViewController.swift */, 97 | DF7F9F0821E37968000F4317 /* AquaMainScrollView.swift */, 98 | DF7F9F0721E37968000F4317 /* AquamanContainView.swift */, 99 | DF7F9F0A21E37968000F4317 /* NSCache+Additional.swift */, 100 | DF7F9F0621E37968000F4317 /* UIScrollView+Additional.swift */, 101 | DF7F9F0521E37968000F4317 /* UIViewController+Additional.swift */, 102 | DF0DDABB21E35C440086663E /* Info.plist */, 103 | ); 104 | path = Aquaman; 105 | sourceTree = ""; 106 | }; 107 | /* End PBXGroup section */ 108 | 109 | /* Begin PBXHeadersBuildPhase section */ 110 | DF0DDAB221E35C440086663E /* Headers */ = { 111 | isa = PBXHeadersBuildPhase; 112 | buildActionMask = 2147483647; 113 | files = ( 114 | DF0DDABC21E35C440086663E /* Aquaman.h in Headers */, 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | /* End PBXHeadersBuildPhase section */ 119 | 120 | /* Begin PBXNativeTarget section */ 121 | DF0DDAB621E35C440086663E /* Aquaman */ = { 122 | isa = PBXNativeTarget; 123 | buildConfigurationList = DF0DDABF21E35C440086663E /* Build configuration list for PBXNativeTarget "Aquaman" */; 124 | buildPhases = ( 125 | 12A91B9C704D6696F36D03EA /* [CP] Check Pods Manifest.lock */, 126 | DF0DDAB221E35C440086663E /* Headers */, 127 | DF0DDAB321E35C440086663E /* Sources */, 128 | DF0DDAB421E35C440086663E /* Frameworks */, 129 | DF0DDAB521E35C440086663E /* Resources */, 130 | ); 131 | buildRules = ( 132 | ); 133 | dependencies = ( 134 | ); 135 | name = Aquaman; 136 | productName = Aquaman; 137 | productReference = DF0DDAB721E35C440086663E /* Aquaman.framework */; 138 | productType = "com.apple.product-type.framework"; 139 | }; 140 | /* End PBXNativeTarget section */ 141 | 142 | /* Begin PBXProject section */ 143 | DF0DDAAE21E35C440086663E /* Project object */ = { 144 | isa = PBXProject; 145 | attributes = { 146 | LastUpgradeCheck = 1010; 147 | ORGANIZATIONNAME = bawn; 148 | TargetAttributes = { 149 | DF0DDAB621E35C440086663E = { 150 | CreatedOnToolsVersion = 10.1; 151 | }; 152 | }; 153 | }; 154 | buildConfigurationList = DF0DDAB121E35C440086663E /* Build configuration list for PBXProject "Aquaman" */; 155 | compatibilityVersion = "Xcode 9.3"; 156 | developmentRegion = en; 157 | hasScannedForEncodings = 0; 158 | knownRegions = ( 159 | en, 160 | Base, 161 | ); 162 | mainGroup = DF0DDAAD21E35C440086663E; 163 | productRefGroup = DF0DDAB821E35C440086663E /* Products */; 164 | projectDirPath = ""; 165 | projectRoot = ""; 166 | targets = ( 167 | DF0DDAB621E35C440086663E /* Aquaman */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXResourcesBuildPhase section */ 173 | DF0DDAB521E35C440086663E /* Resources */ = { 174 | isa = PBXResourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXResourcesBuildPhase section */ 181 | 182 | /* Begin PBXShellScriptBuildPhase section */ 183 | 12A91B9C704D6696F36D03EA /* [CP] Check Pods Manifest.lock */ = { 184 | isa = PBXShellScriptBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | ); 188 | inputFileListPaths = ( 189 | ); 190 | inputPaths = ( 191 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 192 | "${PODS_ROOT}/Manifest.lock", 193 | ); 194 | name = "[CP] Check Pods Manifest.lock"; 195 | outputFileListPaths = ( 196 | ); 197 | outputPaths = ( 198 | "$(DERIVED_FILE_DIR)/Pods-Aquaman-checkManifestLockResult.txt", 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | shellPath = /bin/sh; 202 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 203 | showEnvVarsInLog = 0; 204 | }; 205 | /* End PBXShellScriptBuildPhase section */ 206 | 207 | /* Begin PBXSourcesBuildPhase section */ 208 | DF0DDAB321E35C440086663E /* Sources */ = { 209 | isa = PBXSourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | DF7F9F1121E37969000F4317 /* NSCache+Additional.swift in Sources */, 213 | DF7F9F0D21E37969000F4317 /* UIScrollView+Additional.swift in Sources */, 214 | DF7F9F0F21E37969000F4317 /* AquaMainScrollView.swift in Sources */, 215 | DFFEA09D24A8A5BE0043D896 /* AquamanPageViewController+Additional.swift in Sources */, 216 | DF7F9F1221E37969000F4317 /* AquamanPageViewController.swift in Sources */, 217 | DF7F9F0E21E37969000F4317 /* AquamanContainView.swift in Sources */, 218 | DF7F9F0C21E37969000F4317 /* UIViewController+Additional.swift in Sources */, 219 | DF744C3C239F4F1F003A8EB4 /* AquamanProtocol.swift in Sources */, 220 | DF7F9F1021E37969000F4317 /* AquamanChildViewController.swift in Sources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXSourcesBuildPhase section */ 225 | 226 | /* Begin XCBuildConfiguration section */ 227 | DF0DDABD21E35C440086663E /* Debug */ = { 228 | isa = XCBuildConfiguration; 229 | buildSettings = { 230 | ALWAYS_SEARCH_USER_PATHS = NO; 231 | CLANG_ANALYZER_NONNULL = YES; 232 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 234 | CLANG_CXX_LIBRARY = "libc++"; 235 | CLANG_ENABLE_MODULES = YES; 236 | CLANG_ENABLE_OBJC_ARC = YES; 237 | CLANG_ENABLE_OBJC_WEAK = YES; 238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 239 | CLANG_WARN_BOOL_CONVERSION = YES; 240 | CLANG_WARN_COMMA = YES; 241 | CLANG_WARN_CONSTANT_CONVERSION = YES; 242 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 243 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 244 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 245 | CLANG_WARN_EMPTY_BODY = YES; 246 | CLANG_WARN_ENUM_CONVERSION = YES; 247 | CLANG_WARN_INFINITE_RECURSION = YES; 248 | CLANG_WARN_INT_CONVERSION = YES; 249 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 251 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 253 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 254 | CLANG_WARN_STRICT_PROTOTYPES = YES; 255 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 256 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 257 | CLANG_WARN_UNREACHABLE_CODE = YES; 258 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 259 | CODE_SIGN_IDENTITY = "iPhone Developer"; 260 | COPY_PHASE_STRIP = NO; 261 | CURRENT_PROJECT_VERSION = 1; 262 | DEBUG_INFORMATION_FORMAT = dwarf; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | ENABLE_TESTABILITY = YES; 265 | GCC_C_LANGUAGE_STANDARD = gnu11; 266 | GCC_DYNAMIC_NO_PIC = NO; 267 | GCC_NO_COMMON_BLOCKS = YES; 268 | GCC_OPTIMIZATION_LEVEL = 0; 269 | GCC_PREPROCESSOR_DEFINITIONS = ( 270 | "DEBUG=1", 271 | "$(inherited)", 272 | ); 273 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 274 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 275 | GCC_WARN_UNDECLARED_SELECTOR = YES; 276 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 277 | GCC_WARN_UNUSED_FUNCTION = YES; 278 | GCC_WARN_UNUSED_VARIABLE = YES; 279 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 280 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 281 | MTL_FAST_MATH = YES; 282 | ONLY_ACTIVE_ARCH = YES; 283 | SDKROOT = iphoneos; 284 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 285 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 286 | VERSIONING_SYSTEM = "apple-generic"; 287 | VERSION_INFO_PREFIX = ""; 288 | }; 289 | name = Debug; 290 | }; 291 | DF0DDABE21E35C440086663E /* Release */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | ALWAYS_SEARCH_USER_PATHS = NO; 295 | CLANG_ANALYZER_NONNULL = YES; 296 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 297 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 298 | CLANG_CXX_LIBRARY = "libc++"; 299 | CLANG_ENABLE_MODULES = YES; 300 | CLANG_ENABLE_OBJC_ARC = YES; 301 | CLANG_ENABLE_OBJC_WEAK = YES; 302 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 303 | CLANG_WARN_BOOL_CONVERSION = YES; 304 | CLANG_WARN_COMMA = YES; 305 | CLANG_WARN_CONSTANT_CONVERSION = YES; 306 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 307 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 308 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 309 | CLANG_WARN_EMPTY_BODY = YES; 310 | CLANG_WARN_ENUM_CONVERSION = YES; 311 | CLANG_WARN_INFINITE_RECURSION = YES; 312 | CLANG_WARN_INT_CONVERSION = YES; 313 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 314 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 315 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 316 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 317 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 318 | CLANG_WARN_STRICT_PROTOTYPES = YES; 319 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 320 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 321 | CLANG_WARN_UNREACHABLE_CODE = YES; 322 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 323 | CODE_SIGN_IDENTITY = "iPhone Developer"; 324 | COPY_PHASE_STRIP = NO; 325 | CURRENT_PROJECT_VERSION = 1; 326 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 327 | ENABLE_NS_ASSERTIONS = NO; 328 | ENABLE_STRICT_OBJC_MSGSEND = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu11; 330 | GCC_NO_COMMON_BLOCKS = YES; 331 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 332 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 333 | GCC_WARN_UNDECLARED_SELECTOR = YES; 334 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 335 | GCC_WARN_UNUSED_FUNCTION = YES; 336 | GCC_WARN_UNUSED_VARIABLE = YES; 337 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 338 | MTL_ENABLE_DEBUG_INFO = NO; 339 | MTL_FAST_MATH = YES; 340 | SDKROOT = iphoneos; 341 | SWIFT_COMPILATION_MODE = wholemodule; 342 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 343 | VALIDATE_PRODUCT = YES; 344 | VERSIONING_SYSTEM = "apple-generic"; 345 | VERSION_INFO_PREFIX = ""; 346 | }; 347 | name = Release; 348 | }; 349 | DF0DDAC021E35C440086663E /* Debug */ = { 350 | isa = XCBuildConfiguration; 351 | baseConfigurationReference = 4E2ADF93CCF5BBBB14110499 /* Pods-Aquaman.debug.xcconfig */; 352 | buildSettings = { 353 | CODE_SIGN_IDENTITY = ""; 354 | CODE_SIGN_STYLE = Automatic; 355 | DEFINES_MODULE = YES; 356 | DYLIB_COMPATIBILITY_VERSION = 1; 357 | DYLIB_CURRENT_VERSION = 1; 358 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 359 | INFOPLIST_FILE = Aquaman/Info.plist; 360 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 361 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 362 | LD_RUNPATH_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "@executable_path/Frameworks", 365 | "@loader_path/Frameworks", 366 | ); 367 | PRODUCT_BUNDLE_IDENTIFIER = bawn.Aquaman; 368 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 369 | SKIP_INSTALL = YES; 370 | SWIFT_VERSION = 4.2; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | }; 373 | name = Debug; 374 | }; 375 | DF0DDAC121E35C440086663E /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | baseConfigurationReference = 6DFF8C1B0CD3525BDCE645C5 /* Pods-Aquaman.release.xcconfig */; 378 | buildSettings = { 379 | CODE_SIGN_IDENTITY = ""; 380 | CODE_SIGN_STYLE = Automatic; 381 | DEFINES_MODULE = YES; 382 | DYLIB_COMPATIBILITY_VERSION = 1; 383 | DYLIB_CURRENT_VERSION = 1; 384 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 385 | INFOPLIST_FILE = Aquaman/Info.plist; 386 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 387 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 388 | LD_RUNPATH_SEARCH_PATHS = ( 389 | "$(inherited)", 390 | "@executable_path/Frameworks", 391 | "@loader_path/Frameworks", 392 | ); 393 | PRODUCT_BUNDLE_IDENTIFIER = bawn.Aquaman; 394 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 395 | SKIP_INSTALL = YES; 396 | SWIFT_VERSION = 4.2; 397 | TARGETED_DEVICE_FAMILY = "1,2"; 398 | }; 399 | name = Release; 400 | }; 401 | /* End XCBuildConfiguration section */ 402 | 403 | /* Begin XCConfigurationList section */ 404 | DF0DDAB121E35C440086663E /* Build configuration list for PBXProject "Aquaman" */ = { 405 | isa = XCConfigurationList; 406 | buildConfigurations = ( 407 | DF0DDABD21E35C440086663E /* Debug */, 408 | DF0DDABE21E35C440086663E /* Release */, 409 | ); 410 | defaultConfigurationIsVisible = 0; 411 | defaultConfigurationName = Release; 412 | }; 413 | DF0DDABF21E35C440086663E /* Build configuration list for PBXNativeTarget "Aquaman" */ = { 414 | isa = XCConfigurationList; 415 | buildConfigurations = ( 416 | DF0DDAC021E35C440086663E /* Debug */, 417 | DF0DDAC121E35C440086663E /* Release */, 418 | ); 419 | defaultConfigurationIsVisible = 0; 420 | defaultConfigurationName = Release; 421 | }; 422 | /* End XCConfigurationList section */ 423 | }; 424 | rootObject = DF0DDAAE21E35C440086663E /* Project object */; 425 | } 426 | -------------------------------------------------------------------------------- /Aquaman/Aquaman/AquamanPageViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AquamanPageViewController.swift 3 | // Aquaman 4 | // 5 | // Created by bawn on 2018/12/7. 6 | // Copyright © 2018 bawn. All rights reserved.( http://bawn.github.io ) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import UIKit 27 | 28 | open class AquamanPageViewController: UIViewController, AMPageControllerDataSource, AMPageControllerDelegate { 29 | 30 | public private(set) var currentViewController: (UIViewController & AquamanChildViewController)? 31 | public private(set) var currentIndex = 0 32 | internal var originIndex = 0 33 | 34 | lazy public private(set) var mainScrollView: AquaMainScrollView = { 35 | let scrollView = AquaMainScrollView() 36 | scrollView.delegate = self 37 | scrollView.am_isCanScroll = true 38 | return scrollView 39 | }() 40 | 41 | lazy internal var contentScrollView: UIScrollView = { 42 | let scrollView = UIScrollView() 43 | scrollView.delegate = self 44 | scrollView.bounces = false 45 | scrollView.isPagingEnabled = true 46 | scrollView.scrollsToTop = false 47 | scrollView.showsVerticalScrollIndicator = false 48 | scrollView.showsHorizontalScrollIndicator = false 49 | scrollView.translatesAutoresizingMaskIntoConstraints = false 50 | if let popGesture = navigationController?.interactivePopGestureRecognizer { 51 | scrollView.panGestureRecognizer.require(toFail: popGesture) 52 | } 53 | return scrollView 54 | }() 55 | 56 | private let contentStackView: UIStackView = { 57 | let stackView = UIStackView() 58 | stackView.alignment = .fill 59 | stackView.distribution = .fillEqually 60 | stackView.axis = .horizontal 61 | stackView.translatesAutoresizingMaskIntoConstraints = false 62 | return stackView 63 | }() 64 | 65 | private var contentScrollViewConstraint: NSLayoutConstraint? 66 | private var menuViewConstraint: NSLayoutConstraint? 67 | internal var headerViewConstraint: NSLayoutConstraint? 68 | private var mainScrollViewConstraints: [NSLayoutConstraint] = [] 69 | 70 | internal var headerViewHeight: CGFloat = 0.0 71 | private let headerContentView = UIView() 72 | private let menuContentView = UIView() 73 | private var menuViewHeight: CGFloat = 0.0 74 | internal var menuViewPinHeight: CGFloat = 0.0 75 | internal var sillValue: CGFloat = 0.0 76 | private var childControllerCount = 0 77 | private var countArray = [Int]() 78 | private var containViews = [AquamanContainView]() 79 | internal var currentChildScrollView: UIScrollView? 80 | private var childScrollViewObservation: NSKeyValueObservation? 81 | 82 | private let memoryCache = NSCache() 83 | private weak var dataSource: AMPageControllerDataSource? 84 | private weak var delegate: AMPageControllerDelegate? 85 | 86 | open override var shouldAutomaticallyForwardAppearanceMethods: Bool { 87 | return false 88 | } 89 | 90 | public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 91 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 92 | dataSource = self 93 | delegate = self 94 | } 95 | 96 | public required init?(coder aDecoder: NSCoder) { 97 | super.init(coder: aDecoder) 98 | dataSource = self 99 | delegate = self 100 | } 101 | 102 | open override func viewDidLoad() { 103 | super.viewDidLoad() 104 | 105 | obtainDataSource() 106 | setupOriginContent() 107 | setupDataSource() 108 | view.layoutIfNeeded() 109 | if originIndex > 0 { 110 | setSelect(index: originIndex, animation: false) 111 | } else { 112 | showChildViewContoller(at: originIndex) 113 | didDisplayViewController(at: originIndex) 114 | } 115 | } 116 | 117 | deinit { 118 | childScrollViewObservation?.invalidate() 119 | } 120 | 121 | internal func didDisplayViewController(at index: Int) { 122 | guard childControllerCount > 0 123 | , index >= 0 124 | , index < childControllerCount 125 | , containViews.isEmpty == false else { 126 | return 127 | } 128 | let containView = containViews[index] 129 | currentViewController = containView.viewController 130 | currentChildScrollView = currentViewController?.aquamanChildScrollView() 131 | currentIndex = index 132 | 133 | childScrollViewObservation?.invalidate() 134 | let keyValueObservation = currentChildScrollView?.observe(\.contentOffset, options: [.new, .old], changeHandler: { [weak self] (scrollView, change) in 135 | guard let self = self, change.newValue != change.oldValue else { 136 | return 137 | } 138 | self.childScrollViewDidScroll(scrollView) 139 | }) 140 | childScrollViewObservation = keyValueObservation 141 | 142 | if let viewController = containView.viewController { 143 | pageController(self, didDisplay: viewController, forItemAt: index) 144 | } 145 | } 146 | 147 | 148 | internal func obtainDataSource() { 149 | originIndex = originIndexFor(self) 150 | 151 | headerViewHeight = headerViewHeightFor(self) 152 | 153 | menuViewHeight = menuViewHeightFor(self) 154 | menuViewPinHeight = menuViewPinHeightFor(self) 155 | 156 | childControllerCount = numberOfViewControllers(in: self) 157 | 158 | sillValue = headerViewHeight - menuViewPinHeight 159 | countArray = Array(stride(from: 0, to: childControllerCount, by: 1)) 160 | } 161 | 162 | private func setupOriginContent() { 163 | 164 | mainScrollView.headerViewHeight = headerViewHeight 165 | mainScrollView.menuViewHeight = menuViewHeight 166 | if #available(iOS 13.0, *) { 167 | mainScrollView.contentInsetAdjustmentBehavior = .never 168 | } else { 169 | automaticallyAdjustsScrollViewInsets = false 170 | } 171 | 172 | view.addSubview(mainScrollView) 173 | let contentInset = contentInsetFor(self) 174 | let constraints = [ 175 | mainScrollView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: contentInset.top), 176 | mainScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: contentInset.left), 177 | mainScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -contentInset.bottom), 178 | mainScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -contentInset.right) 179 | ] 180 | mainScrollViewConstraints = constraints 181 | NSLayoutConstraint.activate(constraints) 182 | 183 | 184 | mainScrollView.addSubview(headerContentView) 185 | headerContentView.translatesAutoresizingMaskIntoConstraints = false 186 | 187 | let headerContentViewHeight = headerContentView.heightAnchor.constraint(equalToConstant: headerViewHeight) 188 | headerViewConstraint = headerContentViewHeight 189 | NSLayoutConstraint.activate([ 190 | headerContentView.leadingAnchor.constraint(equalTo: mainScrollView.leadingAnchor), 191 | headerContentView.trailingAnchor.constraint(equalTo: mainScrollView.trailingAnchor), 192 | headerContentView.topAnchor.constraint(equalTo: mainScrollView.topAnchor), 193 | headerContentViewHeight, 194 | ]) 195 | 196 | mainScrollView.addSubview(menuContentView) 197 | menuContentView.translatesAutoresizingMaskIntoConstraints = false 198 | 199 | let menuContentViewHeight = menuContentView.heightAnchor.constraint(equalToConstant: menuViewHeight) 200 | menuViewConstraint = menuContentViewHeight 201 | NSLayoutConstraint.activate([ 202 | menuContentView.leadingAnchor.constraint(equalTo: mainScrollView.leadingAnchor), 203 | menuContentView.trailingAnchor.constraint(equalTo: mainScrollView.trailingAnchor), 204 | menuContentView.widthAnchor.constraint(equalTo: mainScrollView.widthAnchor), 205 | menuContentView.topAnchor.constraint(equalTo: headerContentView.bottomAnchor), 206 | menuContentViewHeight 207 | ]) 208 | 209 | 210 | mainScrollView.addSubview(contentScrollView) 211 | 212 | let contentScrollViewHeight = contentScrollView.heightAnchor.constraint(equalTo: mainScrollView.heightAnchor, constant: -menuViewHeight - menuViewPinHeight) 213 | contentScrollViewConstraint = contentScrollViewHeight 214 | NSLayoutConstraint.activate([ 215 | contentScrollView.leadingAnchor.constraint(equalTo: mainScrollView.leadingAnchor), 216 | contentScrollView.trailingAnchor.constraint(equalTo: mainScrollView.trailingAnchor), 217 | contentScrollView.bottomAnchor.constraint(equalTo: mainScrollView.bottomAnchor), 218 | contentScrollView.widthAnchor.constraint(equalTo: mainScrollView.widthAnchor), 219 | contentScrollView.topAnchor.constraint(equalTo: menuContentView.bottomAnchor), 220 | contentScrollViewHeight 221 | ]) 222 | 223 | 224 | contentScrollView.addSubview(contentStackView) 225 | 226 | NSLayoutConstraint.activate([ 227 | contentStackView.leadingAnchor.constraint(equalTo: contentScrollView.leadingAnchor), 228 | contentStackView.trailingAnchor.constraint(equalTo: contentScrollView.trailingAnchor), 229 | contentStackView.bottomAnchor.constraint(equalTo: contentScrollView.bottomAnchor), 230 | contentStackView.topAnchor.constraint(equalTo: contentScrollView.topAnchor), 231 | contentStackView.heightAnchor.constraint(equalTo: contentScrollView.heightAnchor) 232 | ]) 233 | 234 | mainScrollView.bringSubviewToFront(menuContentView) 235 | mainScrollView.bringSubviewToFront(headerContentView) 236 | } 237 | 238 | internal func updateOriginContent() { 239 | mainScrollView.headerViewHeight = headerViewHeight 240 | mainScrollView.menuViewHeight = menuViewHeight 241 | 242 | if mainScrollViewConstraints.count == 4 { 243 | let contentInset = contentInsetFor(self) 244 | mainScrollViewConstraints.first?.constant = contentInset.top 245 | mainScrollViewConstraints[1].constant = contentInset.left 246 | mainScrollViewConstraints[2].constant = -contentInset.bottom 247 | mainScrollViewConstraints.last?.constant = -contentInset.right 248 | } 249 | headerViewConstraint?.constant = headerViewHeight 250 | menuViewConstraint?.constant = menuViewHeight 251 | contentScrollViewConstraint?.constant = -menuViewHeight - menuViewPinHeight 252 | } 253 | 254 | internal func clear() { 255 | childScrollViewObservation?.invalidate() 256 | 257 | originIndex = 0 258 | currentIndex = 0 259 | 260 | mainScrollView.am_isCanScroll = true 261 | currentChildScrollView?.am_isCanScroll = false 262 | 263 | childControllerCount = 0 264 | 265 | currentViewController = nil 266 | currentChildScrollView?.am_originOffset = nil 267 | currentChildScrollView = nil 268 | 269 | menuContentView.subviews.forEach({$0.removeFromSuperview()}) 270 | headerContentView.subviews.forEach({$0.removeFromSuperview()}) 271 | contentScrollView.contentOffset = .zero 272 | 273 | contentStackView.arrangedSubviews.forEach({$0.removeFromSuperview()}) 274 | clearMemoryCache() 275 | 276 | containViews.forEach({$0.viewController?.clearFromParent()}) 277 | containViews.removeAll() 278 | 279 | countArray.removeAll() 280 | } 281 | 282 | internal func clearMemoryCache() { 283 | countArray.forEach { (index) in 284 | let viewController = memoryCache[index] as? (UIViewController & AquamanChildViewController) 285 | let scrollView = viewController?.aquamanChildScrollView() 286 | scrollView?.am_originOffset = nil 287 | } 288 | memoryCache.removeAllObjects() 289 | } 290 | 291 | internal func setupDataSource() { 292 | memoryCache.countLimit = childControllerCount 293 | 294 | let headerView = headerViewFor(self) 295 | headerContentView.addSubview(headerView) 296 | headerView.translatesAutoresizingMaskIntoConstraints = false 297 | NSLayoutConstraint.activate([ 298 | headerView.leadingAnchor.constraint(equalTo: headerContentView.leadingAnchor), 299 | headerView.trailingAnchor.constraint(equalTo: headerContentView.trailingAnchor), 300 | headerView.bottomAnchor.constraint(equalTo: headerContentView.bottomAnchor), 301 | headerView.topAnchor.constraint(equalTo: headerContentView.topAnchor) 302 | ]) 303 | 304 | let menuView = menuViewFor(self) 305 | menuContentView.addSubview(menuView) 306 | menuView.translatesAutoresizingMaskIntoConstraints = false 307 | NSLayoutConstraint.activate([ 308 | menuView.leadingAnchor.constraint(equalTo: menuContentView.leadingAnchor), 309 | menuView.trailingAnchor.constraint(equalTo: menuContentView.trailingAnchor), 310 | menuView.bottomAnchor.constraint(equalTo: menuContentView.bottomAnchor), 311 | menuView.topAnchor.constraint(equalTo: menuContentView.topAnchor) 312 | ]) 313 | 314 | 315 | countArray.forEach { (_) in 316 | let containView = AquamanContainView() 317 | contentStackView.addArrangedSubview(containView) 318 | NSLayoutConstraint.activate([ 319 | containView.heightAnchor.constraint(equalTo: contentScrollView.heightAnchor), 320 | containView.widthAnchor.constraint(equalTo: contentScrollView.widthAnchor) 321 | ]) 322 | containViews.append(containView) 323 | } 324 | } 325 | 326 | internal func showChildViewContoller(at index: Int) { 327 | guard childControllerCount > 0 328 | , index >= 0 329 | , index < childControllerCount 330 | , containViews.isEmpty == false else { 331 | return 332 | } 333 | 334 | let containView = containViews[index] 335 | guard containView.isEmpty else { 336 | return 337 | } 338 | 339 | let cachedViewContoller = memoryCache[index] as? (UIViewController & AquamanChildViewController) 340 | let viewController = cachedViewContoller != nil ? cachedViewContoller : pageController(self, viewControllerAt: index) 341 | 342 | guard let targetViewController = viewController else { 343 | return 344 | } 345 | pageController(self, willDisplay: targetViewController, forItemAt: index) 346 | 347 | addChild(targetViewController) 348 | targetViewController.beginAppearanceTransition(true, animated: false) 349 | containView.addSubview(targetViewController.view) 350 | targetViewController.view.translatesAutoresizingMaskIntoConstraints = false 351 | NSLayoutConstraint.activate([ 352 | targetViewController.view.leadingAnchor.constraint(equalTo: containView.leadingAnchor), 353 | targetViewController.view.trailingAnchor.constraint(equalTo: containView.trailingAnchor), 354 | targetViewController.view.bottomAnchor.constraint(equalTo: containView.bottomAnchor), 355 | targetViewController.view.topAnchor.constraint(equalTo: containView.topAnchor), 356 | ]) 357 | targetViewController.endAppearanceTransition() 358 | targetViewController.didMove(toParent: self) 359 | targetViewController.view.layoutSubviews() 360 | containView.viewController = targetViewController 361 | 362 | let scrollView = targetViewController.aquamanChildScrollView() 363 | scrollView.am_originOffset = scrollView.contentOffset 364 | 365 | if mainScrollView.contentOffset.y < sillValue { 366 | scrollView.contentOffset = scrollView.am_originOffset ?? .zero 367 | scrollView.am_isCanScroll = false 368 | mainScrollView.am_isCanScroll = true 369 | } 370 | } 371 | 372 | 373 | private func removeChildViewController(at index: Int) { 374 | guard childControllerCount > 0 375 | , index >= 0 376 | , index < childControllerCount 377 | , containViews.isEmpty == false else { 378 | return 379 | } 380 | 381 | let containView = containViews[index] 382 | guard containView.isEmpty == false 383 | , let viewController = containView.viewController else { 384 | return 385 | } 386 | viewController.clearFromParent() 387 | if memoryCache[index] == nil { 388 | pageController(self, willCache: viewController, forItemAt: index) 389 | memoryCache[index] = viewController 390 | } 391 | } 392 | 393 | internal func layoutChildViewControlls() { 394 | countArray.forEach { (index) in 395 | let containView = containViews[index] 396 | let isDisplayingInScreen = containView.displayingIn(view: view, containView: contentScrollView) 397 | isDisplayingInScreen ? showChildViewContoller(at: index) : removeChildViewController(at: index) 398 | } 399 | } 400 | 401 | internal func contentScrollViewDidEndScroll(_ scrollView: UIScrollView) { 402 | let scrollViewWidth = scrollView.bounds.width 403 | guard scrollViewWidth > 0 else { 404 | return 405 | } 406 | 407 | let offsetX = scrollView.contentOffset.x 408 | let index = Int(offsetX / scrollViewWidth) 409 | didDisplayViewController(at: index) 410 | pageController(self, contentScrollViewDidEndScroll: contentScrollView) 411 | } 412 | 413 | 414 | open func pageController(_ pageController: AquamanPageViewController, viewControllerAt index: Int) -> (UIViewController & AquamanChildViewController) { 415 | assertionFailure("Sub-class must implement the AMPageControllerDataSource method") 416 | return UIViewController() as! (UIViewController & AquamanChildViewController) 417 | } 418 | 419 | open func numberOfViewControllers(in pageController: AquamanPageViewController) -> Int { 420 | assertionFailure("Sub-class must implement the AMPageControllerDataSource method") 421 | return 0 422 | } 423 | 424 | open func headerViewFor(_ pageController: AquamanPageViewController) -> UIView { 425 | assertionFailure("Sub-class must implement the AMPageControllerDataSource method") 426 | return UIView() 427 | } 428 | 429 | open func headerViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 430 | assertionFailure("Sub-class must implement the AMPageControllerDataSource method") 431 | return 0 432 | } 433 | 434 | open func menuViewFor(_ pageController: AquamanPageViewController) -> UIView { 435 | assertionFailure("Sub-class must implement the AMPageControllerDataSource method") 436 | return UIView() 437 | } 438 | 439 | open func menuViewHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 440 | assertionFailure("Sub-class must implement the AMPageControllerDataSource method") 441 | return 0 442 | } 443 | 444 | open func originIndexFor(_ pageController: AquamanPageViewController) -> Int { 445 | return 0 446 | } 447 | 448 | open func menuViewPinHeightFor(_ pageController: AquamanPageViewController) -> CGFloat { 449 | return 0 450 | } 451 | 452 | open func pageController(_ pageController: AquamanPageViewController, mainScrollViewDidScroll scrollView: UIScrollView) { 453 | 454 | } 455 | 456 | open func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidEndScroll scrollView: UIScrollView) { 457 | 458 | } 459 | 460 | open func pageController(_ pageController: AquamanPageViewController, contentScrollViewDidScroll scrollView: UIScrollView) { 461 | 462 | } 463 | 464 | open func pageController(_ pageController: AquamanPageViewController, willCache viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 465 | 466 | } 467 | 468 | open func pageController(_ pageController: AquamanPageViewController, willDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 469 | 470 | } 471 | 472 | open func pageController(_ pageController: AquamanPageViewController, didDisplay viewController: (UIViewController & AquamanChildViewController), forItemAt index: Int) { 473 | 474 | } 475 | 476 | open func pageController(_ pageController: AquamanPageViewController, menuView isAdsorption: Bool) { 477 | 478 | } 479 | 480 | open func contentInsetFor(_ pageController: AquamanPageViewController) -> UIEdgeInsets { 481 | return .zero 482 | } 483 | } 484 | 485 | 486 | -------------------------------------------------------------------------------- /Aquaman-Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3E70E23AE12A03F719A61B86 /* Pods_Aquaman_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1818A6060E4BCD927F3FAB53 /* Pods_Aquaman_Demo.framework */; }; 11 | DF457BB323B6131F00708C49 /* Aquaman_DemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF457BB223B6131F00708C49 /* Aquaman_DemoUITests.swift */; }; 12 | DF7AC0272320BB9E002E595E /* TheFlashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7AC0262320BB9E002E595E /* TheFlashViewController.swift */; }; 13 | DF7F9F2121E37EEB000F4317 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F2021E37EEB000F4317 /* AppDelegate.swift */; }; 14 | DF7F9F2821E37EEC000F4317 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DF7F9F2721E37EEC000F4317 /* Assets.xcassets */; }; 15 | DF7F9F2B21E37EEC000F4317 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF7F9F2921E37EEC000F4317 /* LaunchScreen.storyboard */; }; 16 | DF7F9F3E21E37FAA000F4317 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F3221E37FA9000F4317 /* HeaderView.swift */; }; 17 | DF7F9F4321E37FAA000F4317 /* BatmanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F3721E37FA9000F4317 /* BatmanViewController.swift */; }; 18 | DF7F9F4421E37FAA000F4317 /* SupermanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F3821E37FA9000F4317 /* SupermanViewController.swift */; }; 19 | DF7F9F4521E37FAA000F4317 /* PageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F3921E37FA9000F4317 /* PageViewController.swift */; }; 20 | DF7F9F4721E37FAA000F4317 /* WonderWomanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF7F9F3B21E37FA9000F4317 /* WonderWomanViewController.swift */; }; 21 | DF7F9F4B21E37FBB000F4317 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DF7F9F4A21E37FBB000F4317 /* Main.storyboard */; }; 22 | DF931184250C7D5600870847 /* Trident in Frameworks */ = {isa = PBXBuildFile; productRef = DF931183250C7D5600870847 /* Trident */; }; 23 | DF931187250C7DDC00870847 /* Aquaman in Frameworks */ = {isa = PBXBuildFile; productRef = DF931186250C7DDC00870847 /* Aquaman */; }; 24 | DFD4116121E84011006E8D77 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFD4116021E84011006E8D77 /* ViewController.swift */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | DF457BB523B6131F00708C49 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = DF7F9F1521E37EEB000F4317 /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = DF7F9F1C21E37EEB000F4317; 33 | remoteInfo = "Aquaman-Demo"; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXCopyFilesBuildPhase section */ 38 | DF37AB8E23B9F47D0047FEF9 /* Embed Frameworks */ = { 39 | isa = PBXCopyFilesBuildPhase; 40 | buildActionMask = 2147483647; 41 | dstPath = ""; 42 | dstSubfolderSpec = 10; 43 | files = ( 44 | ); 45 | name = "Embed Frameworks"; 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXCopyFilesBuildPhase section */ 49 | 50 | /* Begin PBXFileReference section */ 51 | 1818A6060E4BCD927F3FAB53 /* Pods_Aquaman_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Aquaman_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 3A86685D0616AED53669BBEF /* Pods-Aquaman-Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Aquaman-Demo.release.xcconfig"; path = "Target Support Files/Pods-Aquaman-Demo/Pods-Aquaman-Demo.release.xcconfig"; sourceTree = ""; }; 53 | DF457BB023B6131F00708C49 /* Aquaman-DemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Aquaman-DemoUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | DF457BB223B6131F00708C49 /* Aquaman_DemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Aquaman_DemoUITests.swift; sourceTree = ""; }; 55 | DF457BB423B6131F00708C49 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | DF786CD82230CB8800DD6955 /* Aquaman.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Aquaman.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | DF7AC0262320BB9E002E595E /* TheFlashViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TheFlashViewController.swift; sourceTree = ""; }; 58 | DF7F9F1D21E37EEB000F4317 /* Aquaman-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Aquaman-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | DF7F9F2021E37EEB000F4317 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 60 | DF7F9F2721E37EEC000F4317 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | DF7F9F2A21E37EEC000F4317 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 62 | DF7F9F2C21E37EEC000F4317 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | DF7F9F3221E37FA9000F4317 /* HeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 64 | DF7F9F3721E37FA9000F4317 /* BatmanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatmanViewController.swift; sourceTree = ""; }; 65 | DF7F9F3821E37FA9000F4317 /* SupermanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupermanViewController.swift; sourceTree = ""; }; 66 | DF7F9F3921E37FA9000F4317 /* PageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageViewController.swift; sourceTree = ""; }; 67 | DF7F9F3B21E37FA9000F4317 /* WonderWomanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WonderWomanViewController.swift; sourceTree = ""; }; 68 | DF7F9F4A21E37FBB000F4317 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 69 | DFD4116021E84011006E8D77 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 70 | F5EA41D9B5EC67782591227C /* Pods-Aquaman-Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Aquaman-Demo.debug.xcconfig"; path = "Target Support Files/Pods-Aquaman-Demo/Pods-Aquaman-Demo.debug.xcconfig"; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | DF457BAD23B6131E00708C49 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | DF7F9F1A21E37EEB000F4317 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | DF931187250C7DDC00870847 /* Aquaman in Frameworks */, 86 | 3E70E23AE12A03F719A61B86 /* Pods_Aquaman_Demo.framework in Frameworks */, 87 | DF931184250C7D5600870847 /* Trident in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | 26D8BFA01A1516C315CC832E /* Pods */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | F5EA41D9B5EC67782591227C /* Pods-Aquaman-Demo.debug.xcconfig */, 98 | 3A86685D0616AED53669BBEF /* Pods-Aquaman-Demo.release.xcconfig */, 99 | ); 100 | path = Pods; 101 | sourceTree = ""; 102 | }; 103 | 7E74EA9976E9E47CAA6BDD04 /* Frameworks */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | DF786CD82230CB8800DD6955 /* Aquaman.framework */, 107 | 1818A6060E4BCD927F3FAB53 /* Pods_Aquaman_Demo.framework */, 108 | ); 109 | name = Frameworks; 110 | sourceTree = ""; 111 | }; 112 | DF457BB123B6131F00708C49 /* Aquaman-DemoUITests */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | DF457BB223B6131F00708C49 /* Aquaman_DemoUITests.swift */, 116 | DF457BB423B6131F00708C49 /* Info.plist */, 117 | ); 118 | path = "Aquaman-DemoUITests"; 119 | sourceTree = ""; 120 | }; 121 | DF7F9F1421E37EEB000F4317 = { 122 | isa = PBXGroup; 123 | children = ( 124 | DF7F9F1F21E37EEB000F4317 /* Aquaman-Demo */, 125 | DF457BB123B6131F00708C49 /* Aquaman-DemoUITests */, 126 | DF7F9F1E21E37EEB000F4317 /* Products */, 127 | 7E74EA9976E9E47CAA6BDD04 /* Frameworks */, 128 | 26D8BFA01A1516C315CC832E /* Pods */, 129 | ); 130 | sourceTree = ""; 131 | }; 132 | DF7F9F1E21E37EEB000F4317 /* Products */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | DF7F9F1D21E37EEB000F4317 /* Aquaman-Demo.app */, 136 | DF457BB023B6131F00708C49 /* Aquaman-DemoUITests.xctest */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | DF7F9F1F21E37EEB000F4317 /* Aquaman-Demo */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | DF7F9F2021E37EEB000F4317 /* AppDelegate.swift */, 145 | DF7F9F3921E37FA9000F4317 /* PageViewController.swift */, 146 | DF7F9F3821E37FA9000F4317 /* SupermanViewController.swift */, 147 | DF7F9F3721E37FA9000F4317 /* BatmanViewController.swift */, 148 | DF7F9F3B21E37FA9000F4317 /* WonderWomanViewController.swift */, 149 | DF7AC0262320BB9E002E595E /* TheFlashViewController.swift */, 150 | DF7F9F3221E37FA9000F4317 /* HeaderView.swift */, 151 | DFD4116021E84011006E8D77 /* ViewController.swift */, 152 | DF7F9F4A21E37FBB000F4317 /* Main.storyboard */, 153 | DF7F9F2721E37EEC000F4317 /* Assets.xcassets */, 154 | DF7F9F2921E37EEC000F4317 /* LaunchScreen.storyboard */, 155 | DF7F9F2C21E37EEC000F4317 /* Info.plist */, 156 | ); 157 | path = "Aquaman-Demo"; 158 | sourceTree = ""; 159 | }; 160 | /* End PBXGroup section */ 161 | 162 | /* Begin PBXNativeTarget section */ 163 | DF457BAF23B6131E00708C49 /* Aquaman-DemoUITests */ = { 164 | isa = PBXNativeTarget; 165 | buildConfigurationList = DF457BB923B6131F00708C49 /* Build configuration list for PBXNativeTarget "Aquaman-DemoUITests" */; 166 | buildPhases = ( 167 | DF457BAC23B6131E00708C49 /* Sources */, 168 | DF457BAD23B6131E00708C49 /* Frameworks */, 169 | DF457BAE23B6131E00708C49 /* Resources */, 170 | ); 171 | buildRules = ( 172 | ); 173 | dependencies = ( 174 | DF457BB623B6131F00708C49 /* PBXTargetDependency */, 175 | ); 176 | name = "Aquaman-DemoUITests"; 177 | productName = "Aquaman-DemoUITests"; 178 | productReference = DF457BB023B6131F00708C49 /* Aquaman-DemoUITests.xctest */; 179 | productType = "com.apple.product-type.bundle.ui-testing"; 180 | }; 181 | DF7F9F1C21E37EEB000F4317 /* Aquaman-Demo */ = { 182 | isa = PBXNativeTarget; 183 | buildConfigurationList = DF7F9F2F21E37EEC000F4317 /* Build configuration list for PBXNativeTarget "Aquaman-Demo" */; 184 | buildPhases = ( 185 | 8EF3531CB233F0CACA93EEEF /* [CP] Check Pods Manifest.lock */, 186 | DF7F9F1921E37EEB000F4317 /* Sources */, 187 | DF7F9F1A21E37EEB000F4317 /* Frameworks */, 188 | DF7F9F1B21E37EEB000F4317 /* Resources */, 189 | DF37AB8E23B9F47D0047FEF9 /* Embed Frameworks */, 190 | D65C893F5D7CA8B838CECDC6 /* [CP] Embed Pods Frameworks */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | ); 196 | name = "Aquaman-Demo"; 197 | packageProductDependencies = ( 198 | DF931183250C7D5600870847 /* Trident */, 199 | DF931186250C7DDC00870847 /* Aquaman */, 200 | ); 201 | productName = "Aquaman-Demo"; 202 | productReference = DF7F9F1D21E37EEB000F4317 /* Aquaman-Demo.app */; 203 | productType = "com.apple.product-type.application"; 204 | }; 205 | /* End PBXNativeTarget section */ 206 | 207 | /* Begin PBXProject section */ 208 | DF7F9F1521E37EEB000F4317 /* Project object */ = { 209 | isa = PBXProject; 210 | attributes = { 211 | LastSwiftUpdateCheck = 1130; 212 | LastUpgradeCheck = 1010; 213 | ORGANIZATIONNAME = bawn; 214 | TargetAttributes = { 215 | DF457BAF23B6131E00708C49 = { 216 | CreatedOnToolsVersion = 11.3; 217 | TestTargetID = DF7F9F1C21E37EEB000F4317; 218 | }; 219 | DF7F9F1C21E37EEB000F4317 = { 220 | CreatedOnToolsVersion = 10.1; 221 | }; 222 | }; 223 | }; 224 | buildConfigurationList = DF7F9F1821E37EEB000F4317 /* Build configuration list for PBXProject "Aquaman-Demo" */; 225 | compatibilityVersion = "Xcode 9.3"; 226 | developmentRegion = en; 227 | hasScannedForEncodings = 0; 228 | knownRegions = ( 229 | en, 230 | Base, 231 | ); 232 | mainGroup = DF7F9F1421E37EEB000F4317; 233 | packageReferences = ( 234 | DF931182250C7D5600870847 /* XCRemoteSwiftPackageReference "Trident" */, 235 | DF931185250C7DDC00870847 /* XCRemoteSwiftPackageReference "Aquaman" */, 236 | ); 237 | productRefGroup = DF7F9F1E21E37EEB000F4317 /* Products */; 238 | projectDirPath = ""; 239 | projectRoot = ""; 240 | targets = ( 241 | DF7F9F1C21E37EEB000F4317 /* Aquaman-Demo */, 242 | DF457BAF23B6131E00708C49 /* Aquaman-DemoUITests */, 243 | ); 244 | }; 245 | /* End PBXProject section */ 246 | 247 | /* Begin PBXResourcesBuildPhase section */ 248 | DF457BAE23B6131E00708C49 /* Resources */ = { 249 | isa = PBXResourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | DF7F9F1B21E37EEB000F4317 /* Resources */ = { 256 | isa = PBXResourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | DF7F9F4B21E37FBB000F4317 /* Main.storyboard in Resources */, 260 | DF7F9F2B21E37EEC000F4317 /* LaunchScreen.storyboard in Resources */, 261 | DF7F9F2821E37EEC000F4317 /* Assets.xcassets in Resources */, 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | /* End PBXResourcesBuildPhase section */ 266 | 267 | /* Begin PBXShellScriptBuildPhase section */ 268 | 8EF3531CB233F0CACA93EEEF /* [CP] Check Pods Manifest.lock */ = { 269 | isa = PBXShellScriptBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | ); 273 | inputFileListPaths = ( 274 | ); 275 | inputPaths = ( 276 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 277 | "${PODS_ROOT}/Manifest.lock", 278 | ); 279 | name = "[CP] Check Pods Manifest.lock"; 280 | outputFileListPaths = ( 281 | ); 282 | outputPaths = ( 283 | "$(DERIVED_FILE_DIR)/Pods-Aquaman-Demo-checkManifestLockResult.txt", 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | shellPath = /bin/sh; 287 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 288 | showEnvVarsInLog = 0; 289 | }; 290 | D65C893F5D7CA8B838CECDC6 /* [CP] Embed Pods Frameworks */ = { 291 | isa = PBXShellScriptBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | ); 295 | inputFileListPaths = ( 296 | "${PODS_ROOT}/Target Support Files/Pods-Aquaman-Demo/Pods-Aquaman-Demo-frameworks-${CONFIGURATION}-input-files.xcfilelist", 297 | ); 298 | name = "[CP] Embed Pods Frameworks"; 299 | outputFileListPaths = ( 300 | "${PODS_ROOT}/Target Support Files/Pods-Aquaman-Demo/Pods-Aquaman-Demo-frameworks-${CONFIGURATION}-output-files.xcfilelist", 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | shellPath = /bin/sh; 304 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Aquaman-Demo/Pods-Aquaman-Demo-frameworks.sh\"\n"; 305 | showEnvVarsInLog = 0; 306 | }; 307 | /* End PBXShellScriptBuildPhase section */ 308 | 309 | /* Begin PBXSourcesBuildPhase section */ 310 | DF457BAC23B6131E00708C49 /* Sources */ = { 311 | isa = PBXSourcesBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | DF457BB323B6131F00708C49 /* Aquaman_DemoUITests.swift in Sources */, 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | DF7F9F1921E37EEB000F4317 /* Sources */ = { 319 | isa = PBXSourcesBuildPhase; 320 | buildActionMask = 2147483647; 321 | files = ( 322 | DF7F9F4521E37FAA000F4317 /* PageViewController.swift in Sources */, 323 | DF7AC0272320BB9E002E595E /* TheFlashViewController.swift in Sources */, 324 | DF7F9F4721E37FAA000F4317 /* WonderWomanViewController.swift in Sources */, 325 | DF7F9F3E21E37FAA000F4317 /* HeaderView.swift in Sources */, 326 | DFD4116121E84011006E8D77 /* ViewController.swift in Sources */, 327 | DF7F9F2121E37EEB000F4317 /* AppDelegate.swift in Sources */, 328 | DF7F9F4321E37FAA000F4317 /* BatmanViewController.swift in Sources */, 329 | DF7F9F4421E37FAA000F4317 /* SupermanViewController.swift in Sources */, 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXSourcesBuildPhase section */ 334 | 335 | /* Begin PBXTargetDependency section */ 336 | DF457BB623B6131F00708C49 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = DF7F9F1C21E37EEB000F4317 /* Aquaman-Demo */; 339 | targetProxy = DF457BB523B6131F00708C49 /* PBXContainerItemProxy */; 340 | }; 341 | /* End PBXTargetDependency section */ 342 | 343 | /* Begin PBXVariantGroup section */ 344 | DF7F9F2921E37EEC000F4317 /* LaunchScreen.storyboard */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | DF7F9F2A21E37EEC000F4317 /* Base */, 348 | ); 349 | name = LaunchScreen.storyboard; 350 | sourceTree = ""; 351 | }; 352 | /* End PBXVariantGroup section */ 353 | 354 | /* Begin XCBuildConfiguration section */ 355 | DF457BB723B6131F00708C49 /* Debug */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | CODE_SIGN_STYLE = Automatic; 359 | DEVELOPMENT_TEAM = 8246L2QR6A; 360 | INFOPLIST_FILE = "Aquaman-DemoUITests/Info.plist"; 361 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 362 | LD_RUNPATH_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "@executable_path/Frameworks", 365 | "@loader_path/Frameworks", 366 | ); 367 | PRODUCT_BUNDLE_IDENTIFIER = "bawn.Aquaman-DemoUITests"; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | SWIFT_VERSION = 5.0; 370 | TARGETED_DEVICE_FAMILY = "1,2"; 371 | TEST_TARGET_NAME = "Aquaman-Demo"; 372 | }; 373 | name = Debug; 374 | }; 375 | DF457BB823B6131F00708C49 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | CODE_SIGN_STYLE = Automatic; 379 | DEVELOPMENT_TEAM = 8246L2QR6A; 380 | INFOPLIST_FILE = "Aquaman-DemoUITests/Info.plist"; 381 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 382 | LD_RUNPATH_SEARCH_PATHS = ( 383 | "$(inherited)", 384 | "@executable_path/Frameworks", 385 | "@loader_path/Frameworks", 386 | ); 387 | PRODUCT_BUNDLE_IDENTIFIER = "bawn.Aquaman-DemoUITests"; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | SWIFT_VERSION = 5.0; 390 | TARGETED_DEVICE_FAMILY = "1,2"; 391 | TEST_TARGET_NAME = "Aquaman-Demo"; 392 | }; 393 | name = Release; 394 | }; 395 | DF7F9F2D21E37EEC000F4317 /* Debug */ = { 396 | isa = XCBuildConfiguration; 397 | buildSettings = { 398 | ALWAYS_SEARCH_USER_PATHS = NO; 399 | CLANG_ANALYZER_NONNULL = YES; 400 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 401 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 402 | CLANG_CXX_LIBRARY = "libc++"; 403 | CLANG_ENABLE_MODULES = YES; 404 | CLANG_ENABLE_OBJC_ARC = YES; 405 | CLANG_ENABLE_OBJC_WEAK = YES; 406 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 407 | CLANG_WARN_BOOL_CONVERSION = YES; 408 | CLANG_WARN_COMMA = YES; 409 | CLANG_WARN_CONSTANT_CONVERSION = YES; 410 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 411 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 412 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 413 | CLANG_WARN_EMPTY_BODY = YES; 414 | CLANG_WARN_ENUM_CONVERSION = YES; 415 | CLANG_WARN_INFINITE_RECURSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 418 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 419 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 422 | CLANG_WARN_STRICT_PROTOTYPES = YES; 423 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 424 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 425 | CLANG_WARN_UNREACHABLE_CODE = YES; 426 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 427 | CODE_SIGN_IDENTITY = "iPhone Developer"; 428 | COPY_PHASE_STRIP = NO; 429 | DEBUG_INFORMATION_FORMAT = dwarf; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | ENABLE_TESTABILITY = YES; 432 | GCC_C_LANGUAGE_STANDARD = gnu11; 433 | GCC_DYNAMIC_NO_PIC = NO; 434 | GCC_NO_COMMON_BLOCKS = YES; 435 | GCC_OPTIMIZATION_LEVEL = 0; 436 | GCC_PREPROCESSOR_DEFINITIONS = ( 437 | "DEBUG=1", 438 | "$(inherited)", 439 | ); 440 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 441 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 442 | GCC_WARN_UNDECLARED_SELECTOR = YES; 443 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 444 | GCC_WARN_UNUSED_FUNCTION = YES; 445 | GCC_WARN_UNUSED_VARIABLE = YES; 446 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 447 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 448 | MTL_FAST_MATH = YES; 449 | ONLY_ACTIVE_ARCH = YES; 450 | SDKROOT = iphoneos; 451 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 452 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 453 | }; 454 | name = Debug; 455 | }; 456 | DF7F9F2E21E37EEC000F4317 /* Release */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | ALWAYS_SEARCH_USER_PATHS = NO; 460 | CLANG_ANALYZER_NONNULL = YES; 461 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 462 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 463 | CLANG_CXX_LIBRARY = "libc++"; 464 | CLANG_ENABLE_MODULES = YES; 465 | CLANG_ENABLE_OBJC_ARC = YES; 466 | CLANG_ENABLE_OBJC_WEAK = YES; 467 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 468 | CLANG_WARN_BOOL_CONVERSION = YES; 469 | CLANG_WARN_COMMA = YES; 470 | CLANG_WARN_CONSTANT_CONVERSION = YES; 471 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 472 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 473 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 474 | CLANG_WARN_EMPTY_BODY = YES; 475 | CLANG_WARN_ENUM_CONVERSION = YES; 476 | CLANG_WARN_INFINITE_RECURSION = YES; 477 | CLANG_WARN_INT_CONVERSION = YES; 478 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 479 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 480 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 481 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 482 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 483 | CLANG_WARN_STRICT_PROTOTYPES = YES; 484 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 485 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 486 | CLANG_WARN_UNREACHABLE_CODE = YES; 487 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 488 | CODE_SIGN_IDENTITY = "iPhone Developer"; 489 | COPY_PHASE_STRIP = NO; 490 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 491 | ENABLE_NS_ASSERTIONS = NO; 492 | ENABLE_STRICT_OBJC_MSGSEND = YES; 493 | GCC_C_LANGUAGE_STANDARD = gnu11; 494 | GCC_NO_COMMON_BLOCKS = YES; 495 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 496 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 497 | GCC_WARN_UNDECLARED_SELECTOR = YES; 498 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 499 | GCC_WARN_UNUSED_FUNCTION = YES; 500 | GCC_WARN_UNUSED_VARIABLE = YES; 501 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 502 | MTL_ENABLE_DEBUG_INFO = NO; 503 | MTL_FAST_MATH = YES; 504 | SDKROOT = iphoneos; 505 | SWIFT_COMPILATION_MODE = wholemodule; 506 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 507 | VALIDATE_PRODUCT = YES; 508 | }; 509 | name = Release; 510 | }; 511 | DF7F9F3021E37EEC000F4317 /* Debug */ = { 512 | isa = XCBuildConfiguration; 513 | baseConfigurationReference = F5EA41D9B5EC67782591227C /* Pods-Aquaman-Demo.debug.xcconfig */; 514 | buildSettings = { 515 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 516 | CODE_SIGN_STYLE = Automatic; 517 | DEVELOPMENT_TEAM = 8246L2QR6A; 518 | INFOPLIST_FILE = "Aquaman-Demo/Info.plist"; 519 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 520 | LD_RUNPATH_SEARCH_PATHS = ( 521 | "$(inherited)", 522 | "@executable_path/Frameworks", 523 | ); 524 | PRODUCT_BUNDLE_IDENTIFIER = "bawn.Aquaman-Demo"; 525 | PRODUCT_NAME = "$(TARGET_NAME)"; 526 | SWIFT_VERSION = 4.2; 527 | TARGETED_DEVICE_FAMILY = "1,2"; 528 | }; 529 | name = Debug; 530 | }; 531 | DF7F9F3121E37EEC000F4317 /* Release */ = { 532 | isa = XCBuildConfiguration; 533 | baseConfigurationReference = 3A86685D0616AED53669BBEF /* Pods-Aquaman-Demo.release.xcconfig */; 534 | buildSettings = { 535 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 536 | CODE_SIGN_STYLE = Automatic; 537 | DEVELOPMENT_TEAM = 8246L2QR6A; 538 | INFOPLIST_FILE = "Aquaman-Demo/Info.plist"; 539 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 540 | LD_RUNPATH_SEARCH_PATHS = ( 541 | "$(inherited)", 542 | "@executable_path/Frameworks", 543 | ); 544 | PRODUCT_BUNDLE_IDENTIFIER = "bawn.Aquaman-Demo"; 545 | PRODUCT_NAME = "$(TARGET_NAME)"; 546 | SWIFT_VERSION = 4.2; 547 | TARGETED_DEVICE_FAMILY = "1,2"; 548 | }; 549 | name = Release; 550 | }; 551 | /* End XCBuildConfiguration section */ 552 | 553 | /* Begin XCConfigurationList section */ 554 | DF457BB923B6131F00708C49 /* Build configuration list for PBXNativeTarget "Aquaman-DemoUITests" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | DF457BB723B6131F00708C49 /* Debug */, 558 | DF457BB823B6131F00708C49 /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | DF7F9F1821E37EEB000F4317 /* Build configuration list for PBXProject "Aquaman-Demo" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | DF7F9F2D21E37EEC000F4317 /* Debug */, 567 | DF7F9F2E21E37EEC000F4317 /* Release */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | DF7F9F2F21E37EEC000F4317 /* Build configuration list for PBXNativeTarget "Aquaman-Demo" */ = { 573 | isa = XCConfigurationList; 574 | buildConfigurations = ( 575 | DF7F9F3021E37EEC000F4317 /* Debug */, 576 | DF7F9F3121E37EEC000F4317 /* Release */, 577 | ); 578 | defaultConfigurationIsVisible = 0; 579 | defaultConfigurationName = Release; 580 | }; 581 | /* End XCConfigurationList section */ 582 | 583 | /* Begin XCRemoteSwiftPackageReference section */ 584 | DF931182250C7D5600870847 /* XCRemoteSwiftPackageReference "Trident" */ = { 585 | isa = XCRemoteSwiftPackageReference; 586 | repositoryURL = "https://github.com/bawn/Trident.git"; 587 | requirement = { 588 | kind = upToNextMajorVersion; 589 | minimumVersion = 0.7.0; 590 | }; 591 | }; 592 | DF931185250C7DDC00870847 /* XCRemoteSwiftPackageReference "Aquaman" */ = { 593 | isa = XCRemoteSwiftPackageReference; 594 | repositoryURL = "https://github.com/bawn/Aquaman.git"; 595 | requirement = { 596 | kind = upToNextMajorVersion; 597 | minimumVersion = 0.1.3; 598 | }; 599 | }; 600 | /* End XCRemoteSwiftPackageReference section */ 601 | 602 | /* Begin XCSwiftPackageProductDependency section */ 603 | DF931183250C7D5600870847 /* Trident */ = { 604 | isa = XCSwiftPackageProductDependency; 605 | package = DF931182250C7D5600870847 /* XCRemoteSwiftPackageReference "Trident" */; 606 | productName = Trident; 607 | }; 608 | DF931186250C7DDC00870847 /* Aquaman */ = { 609 | isa = XCSwiftPackageProductDependency; 610 | package = DF931185250C7DDC00870847 /* XCRemoteSwiftPackageReference "Aquaman" */; 611 | productName = Aquaman; 612 | }; 613 | /* End XCSwiftPackageProductDependency section */ 614 | }; 615 | rootObject = DF7F9F1521E37EEB000F4317 /* Project object */; 616 | } 617 | -------------------------------------------------------------------------------- /Aquaman-Demo/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | --------------------------------------------------------------------------------