From 65b4085a8fbde581d3d4b352539cba0edee39caf Mon Sep 17 00:00:00 2001 From: Jiar Date: Wed, 6 May 2020 17:45:33 +0800 Subject: [PATCH] detach the switcher control --- Example.xcodeproj/project.pbxproj | 26 +++- ...seSegementSlideDefaultViewController.swift | 89 +++++++++++ .../BaseSegementSlideViewController.swift | 15 +- ...ansparentSlideDefaultViewController.swift} | 20 +-- Example/Example.entitlements | 10 ++ .../ContentOptionalViewController.swift | 6 +- .../Main/Content/ContentViewController.swift | 9 +- .../Main/Explore/ExploreViewController.swift | 6 +- Example/Main/Home/HomeViewController.swift | 4 +- .../LanguageCenterViewController.swift | 20 +-- Example/Main/Mine/MineViewController.swift | 6 +- .../Main/Notice/NoticeViewController.swift | 15 +- Example/Main/Post/PostViewController.swift | 4 +- Example/Manager/ConfigManager.swift | 4 +- .../Util/UINavigationController+Swizzle.swift | 3 +- Source/Content/SegementSlideContentView.swift | 8 +- .../SegementSlideDefaultViewController.swift | 76 ++++++++++ Source/General/SegementSlideScrollView.swift | 4 +- ...SegementSlideViewController+delegate.swift | 24 +-- .../SegementSlideViewController+scroll.swift | 22 +-- .../SegementSlideViewController+setup.swift | 140 +++++++++--------- .../General/SegementSlideViewController.swift | 61 +++----- ...ransparentSlideDefaultViewController.swift | 76 ++++++++++ .../TransparentSlideViewController.swift | 2 +- Source/Header/SegementSlideHeaderView.swift | 18 +-- Source/{Badge => Switcher}/BadgeView.swift | 16 +- .../SegementSlideDefaultSwitcherConfig.swift} | 6 +- .../SegementSlideDefaultSwitcherView+ex.swift | 31 ++++ .../SegementSlideDefaultSwitcherView.swift} | 26 ++-- .../SegementSlideSwitcherDelegate.swift | 42 ++++++ .../String+Bounding.swift | 0 31 files changed, 544 insertions(+), 245 deletions(-) create mode 100644 Example/Base/BaseSegementSlideDefaultViewController.swift rename Example/Base/{BaseTransparentSlideViewController.swift => BaseTransparentSlideDefaultViewController.swift} (82%) create mode 100644 Example/Example.entitlements create mode 100644 Source/General/SegementSlideDefaultViewController.swift create mode 100644 Source/General/TransparentSlideDefaultViewController.swift rename Source/{Badge => Switcher}/BadgeView.swift (94%) rename Source/{Segement/SegementSlideSwitcherConfig.swift => Switcher/SegementSlideDefaultSwitcherConfig.swift} (93%) create mode 100644 Source/Switcher/SegementSlideDefaultSwitcherView+ex.swift rename Source/{Segement/SegementSlideSwitcherView.swift => Switcher/SegementSlideDefaultSwitcherView.swift} (92%) create mode 100644 Source/Switcher/SegementSlideSwitcherDelegate.swift rename Source/{Utility => Switcher}/String+Bounding.swift (100%) diff --git a/Example.xcodeproj/project.pbxproj b/Example.xcodeproj/project.pbxproj index 301fdde..91577f6 100644 --- a/Example.xcodeproj/project.pbxproj +++ b/Example.xcodeproj/project.pbxproj @@ -15,7 +15,7 @@ 804CC4DA21C1531D007EEBF8 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804CC4D921C1531D007EEBF8 /* HomeViewController.swift */; }; 804CC4DC21C1532F007EEBF8 /* ExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804CC4DB21C1532F007EEBF8 /* ExploreViewController.swift */; }; 804CC4DE21C15339007EEBF8 /* MineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804CC4DD21C15339007EEBF8 /* MineViewController.swift */; }; - 805C1D9921C7C86A00991D07 /* BaseTransparentSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 805C1D9821C7C86A00991D07 /* BaseTransparentSlideViewController.swift */; }; + 805C1D9921C7C86A00991D07 /* BaseTransparentSlideDefaultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 805C1D9821C7C86A00991D07 /* BaseTransparentSlideDefaultViewController.swift */; }; 806518D221F309A00036FF5F /* ContentOptionalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 806518D121F309A00036FF5F /* ContentOptionalViewController.swift */; }; 806518D621F30A1D0036FF5F /* NoticeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 806518D521F30A1D0036FF5F /* NoticeViewController.swift */; }; 806518D821F317050036FF5F /* UINavigationController+Swizzle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 806518D721F317050036FF5F /* UINavigationController+Swizzle.swift */; }; @@ -34,7 +34,7 @@ 80B6C3F021C20052007C958F /* ContentViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B6C3EE21C20052007C958F /* ContentViewCell.swift */; }; 80B6C3F121C20052007C958F /* ContentViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80B6C3EF21C20052007C958F /* ContentViewCell.xib */; }; 80B6C3F921C2943E007C958F /* CALayer+Sketch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B6C3F821C2943E007C958F /* CALayer+Sketch.swift */; }; - 80B6C3FB21C295ED007C958F /* BaseSegementSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B6C3FA21C295ED007C958F /* BaseSegementSlideViewController.swift */; }; + 80B6C3FB21C295ED007C958F /* BaseSegementSlideDefaultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B6C3FA21C295ED007C958F /* BaseSegementSlideDefaultViewController.swift */; }; 80B6C3FE21C29EEA007C958F /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B6C3FD21C29EEA007C958F /* DataManager.swift */; }; 80B6C40521C2A600007C958F /* bg_computer.png in Resources */ = {isa = PBXBuildFile; fileRef = 80B6C40421C2A600007C958F /* bg_computer.png */; }; 80F3D6B821D789D6005D649A /* BadgeType+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F3D6B721D789D6005D649A /* BadgeType+Random.swift */; }; @@ -63,7 +63,7 @@ 804CC4D921C1531D007EEBF8 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 804CC4DB21C1532F007EEBF8 /* ExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreViewController.swift; sourceTree = ""; }; 804CC4DD21C15339007EEBF8 /* MineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MineViewController.swift; sourceTree = ""; }; - 805C1D9821C7C86A00991D07 /* BaseTransparentSlideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTransparentSlideViewController.swift; sourceTree = ""; }; + 805C1D9821C7C86A00991D07 /* BaseTransparentSlideDefaultViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTransparentSlideDefaultViewController.swift; sourceTree = ""; }; 806518D121F309A00036FF5F /* ContentOptionalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentOptionalViewController.swift; sourceTree = ""; }; 806518D521F30A1D0036FF5F /* NoticeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeViewController.swift; sourceTree = ""; }; 806518D721F317050036FF5F /* UINavigationController+Swizzle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Swizzle.swift"; sourceTree = ""; }; @@ -84,9 +84,10 @@ 80B6C3EE21C20052007C958F /* ContentViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewCell.swift; sourceTree = ""; }; 80B6C3EF21C20052007C958F /* ContentViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ContentViewCell.xib; sourceTree = ""; }; 80B6C3F821C2943E007C958F /* CALayer+Sketch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+Sketch.swift"; sourceTree = ""; }; - 80B6C3FA21C295ED007C958F /* BaseSegementSlideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseSegementSlideViewController.swift; sourceTree = ""; }; + 80B6C3FA21C295ED007C958F /* BaseSegementSlideDefaultViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseSegementSlideDefaultViewController.swift; sourceTree = ""; }; 80B6C3FD21C29EEA007C958F /* DataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = ""; }; 80B6C40421C2A600007C958F /* bg_computer.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bg_computer.png; sourceTree = ""; }; + 80D6BC6E23949C6000B0E2F8 /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; 80F3D6B721D789D6005D649A /* BadgeType+Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BadgeType+Random.swift"; sourceTree = ""; }; 8347D796F78F8EF653440011 /* Pods_ExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9BFDF05ED108B36DDF0BD851 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; @@ -146,6 +147,7 @@ 804CC4C621C14AC4007EEBF8 /* Example */ = { isa = PBXGroup; children = ( + 80D6BC6E23949C6000B0E2F8 /* Example.entitlements */, 806518D421F309F10036FF5F /* Main */, 80B6C3F221C20D76007C958F /* Base */, 80B6C3FC21C29ED8007C958F /* Manager */, @@ -253,8 +255,8 @@ children = ( 8066CA9B236FD48D002D1E08 /* BaseNavigationController.swift */, 802DF82C2225326D00533012 /* BaseTableViewController.swift */, - 80B6C3FA21C295ED007C958F /* BaseSegementSlideViewController.swift */, - 805C1D9821C7C86A00991D07 /* BaseTransparentSlideViewController.swift */, + 80B6C3FA21C295ED007C958F /* BaseSegementSlideDefaultViewController.swift */, + 805C1D9821C7C86A00991D07 /* BaseTransparentSlideDefaultViewController.swift */, ); path = Base; sourceTree = ""; @@ -477,7 +479,7 @@ 80B6C3ED21C1FAB5007C958F /* ContentViewController.swift in Sources */, 80F3D6B821D789D6005D649A /* BadgeType+Random.swift in Sources */, 8099833C2249306E00C36D4B /* ConfigManager.swift in Sources */, - 805C1D9921C7C86A00991D07 /* BaseTransparentSlideViewController.swift in Sources */, + 805C1D9921C7C86A00991D07 /* BaseTransparentSlideDefaultViewController.swift in Sources */, 80B6C3FE21C29EEA007C958F /* DataManager.swift in Sources */, 806518D821F317050036FF5F /* UINavigationController+Swizzle.swift in Sources */, 804CC4C821C14AC4007EEBF8 /* AppDelegate.swift in Sources */, @@ -492,7 +494,7 @@ 807A36DF21C359D3004675BC /* AppManager.swift in Sources */, 804CC4DC21C1532F007EEBF8 /* ExploreViewController.swift in Sources */, 806518D221F309A00036FF5F /* ContentOptionalViewController.swift in Sources */, - 80B6C3FB21C295ED007C958F /* BaseSegementSlideViewController.swift in Sources */, + 80B6C3FB21C295ED007C958F /* BaseSegementSlideDefaultViewController.swift in Sources */, 804CC4DE21C15339007EEBF8 /* MineViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -650,7 +652,10 @@ baseConfigurationReference = DFC82FD65CC44CDF1D54158C /* Pods-Example.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; DEVELOPMENT_TEAM = D4MTBNMTU5; INFOPLIST_FILE = "$(SRCROOT)/Example/Resources/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -661,6 +666,7 @@ MARKETING_VERSION = 2.2.3; PRODUCT_BUNDLE_IDENTIFIER = me.jiar.Example; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTS_MACCATALYST = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -671,7 +677,10 @@ baseConfigurationReference = 9BFDF05ED108B36DDF0BD851 /* Pods-Example.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; DEVELOPMENT_TEAM = D4MTBNMTU5; INFOPLIST_FILE = "$(SRCROOT)/Example/Resources/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -682,6 +691,7 @@ MARKETING_VERSION = 2.2.3; PRODUCT_BUNDLE_IDENTIFIER = me.jiar.Example; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTS_MACCATALYST = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/Example/Base/BaseSegementSlideDefaultViewController.swift b/Example/Base/BaseSegementSlideDefaultViewController.swift new file mode 100644 index 0000000..0ae2b5c --- /dev/null +++ b/Example/Base/BaseSegementSlideDefaultViewController.swift @@ -0,0 +1,89 @@ +// +// BaseSegementSlideDefaultViewController.swift +// Example +// +// Created by Jiar on 2018/12/13. +// Copyright © 2018 Jiar. All rights reserved. +// + +import UIKit +import SegementSlide + +class BaseSegementSlideDefaultViewController: SegementSlideDefaultViewController { + + override var switcherConfig: SegementSlideDefaultSwitcherConfig { + return ConfigManager.shared.switcherConfig + } + + override func scrollViewDidScroll(_ scrollView: UIScrollView, isParent: Bool) { + super.scrollViewDidScroll(scrollView, isParent: isParent) + guard isParent else { return } + updateNavigationBarStyle(scrollView) + } + + private func updateNavigationBarStyle(_ scrollView: UIScrollView) { + if scrollView.contentOffset.y > headerStickyHeight { + switcherView.layer.applySketchShadow(color: .black, alpha: 0.03, x: 0, y: 2.5, blur: 5) + switcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") + } else { + switcherView.layer.applySketchShadow(color: .clear, alpha: 0, x: 0, y: 0, blur: 0) + switcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") + } + } + + private func generateFadeAnimation() -> CATransition { + let fadeTextAnimation = CATransition() + fadeTextAnimation.duration = 0.25 + fadeTextAnimation.type = .fade + return fadeTextAnimation + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + debugPrint("\(type(of: self)) - \(String(format: "%p", self)) - \(#function)") + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + debugPrint("\(type(of: self)) - \(String(format: "%p", self)) - \(#function)") + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + debugPrint("\(type(of: self)) - \(String(format: "%p", self)) - \(#function)") + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + debugPrint("\(type(of: self)) - \(String(format: "%p", self)) - \(#function)") + } + + override func viewDidLoad() { + super.viewDidLoad() + debugPrint("\(type(of: self)) - \(String(format: "%p", self)) - \(#function)") + view.backgroundColor = .white + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "more", style: .plain, target: self, action: #selector(moreAction)) + } + + @objc + private func moreAction() { + let viewController: UIViewController + switch Int.random(in: 0..<8) { + case 0..<4: + viewController = NoticeViewController(selectedIndex: Int.random(in: 0.. headerStickyHeight { - slideSwitcherView.layer.applySketchShadow(color: .black, alpha: 0.03, x: 0, y: 2.5, blur: 5) - slideSwitcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") + switcherView.layer.applySketchShadow(color: .black, alpha: 0.03, x: 0, y: 2.5, blur: 5) + switcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") } else { - slideSwitcherView.layer.applySketchShadow(color: .clear, alpha: 0, x: 0, y: 0, blur: 0) - slideSwitcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") + switcherView.layer.applySketchShadow(color: .clear, alpha: 0, x: 0, y: 0, blur: 0) + switcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") } } @@ -65,7 +65,8 @@ class BaseSegementSlideViewController: SegementSlideViewController { navigationItem.rightBarButtonItem = UIBarButtonItem(title: "more", style: .plain, target: self, action: #selector(moreAction)) } - @objc private func moreAction() { + @objc + private func moreAction() { let viewController: UIViewController switch Int.random(in: 0..<8) { case 0..<4: diff --git a/Example/Base/BaseTransparentSlideViewController.swift b/Example/Base/BaseTransparentSlideDefaultViewController.swift similarity index 82% rename from Example/Base/BaseTransparentSlideViewController.swift rename to Example/Base/BaseTransparentSlideDefaultViewController.swift index 34580b7..63faa6b 100644 --- a/Example/Base/BaseTransparentSlideViewController.swift +++ b/Example/Base/BaseTransparentSlideDefaultViewController.swift @@ -1,5 +1,5 @@ // -// BaseTransparentSlideViewController.swift +// BaseTransparentSlideDefaultViewController.swift // Example // // Created by Jiar on 2018/12/17. @@ -9,9 +9,9 @@ import UIKit import SegementSlide -class BaseTransparentSlideViewController: TransparentSlideViewController { +class BaseTransparentSlideDefaultViewController: TransparentSlideDefaultViewController { - override var switcherConfig: SegementSlideSwitcherConfig { + override var switcherConfig: SegementSlideDefaultSwitcherConfig { return ConfigManager.shared.switcherConfig } @@ -23,11 +23,11 @@ class BaseTransparentSlideViewController: TransparentSlideViewController { private func updateNavigationBarStyle(_ scrollView: UIScrollView) { if scrollView.contentOffset.y > headerStickyHeight { - slideSwitcherView.layer.applySketchShadow(color: .black, alpha: 0.03, x: 0, y: 2.5, blur: 5) - slideSwitcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") + switcherView.layer.applySketchShadow(color: .black, alpha: 0.03, x: 0, y: 2.5, blur: 5) + switcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") } else { - slideSwitcherView.layer.applySketchShadow(color: .clear, alpha: 0, x: 0, y: 0, blur: 0) - slideSwitcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") + switcherView.layer.applySketchShadow(color: .clear, alpha: 0, x: 0, y: 0, blur: 0) + switcherView.layer.add(generateFadeAnimation(), forKey: "reloadSwitcherView") } } @@ -69,11 +69,13 @@ class BaseTransparentSlideViewController: TransparentSlideViewController { } } - @objc private func reloadAction() { + @objc + private func reloadAction() { reloadData() } - @objc private func moreAction() { + @objc + private func moreAction() { let viewController: UIViewController switch Int.random(in: 0..<8) { case 0..<4: diff --git a/Example/Example.entitlements b/Example/Example.entitlements new file mode 100644 index 0000000..ee95ab7 --- /dev/null +++ b/Example/Example.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/Example/Main/Content/ContentOptionalViewController.swift b/Example/Main/Content/ContentOptionalViewController.swift index 0851664..609d851 100644 --- a/Example/Main/Content/ContentOptionalViewController.swift +++ b/Example/Main/Content/ContentOptionalViewController.swift @@ -47,7 +47,8 @@ class ContentOptionalViewController: BaseTableViewController, SegementSlideConte tableView.mj_header.beginRefreshing() } - @objc private func refreshAction() { + @objc + private func refreshAction() { if tableView.mj_footer.isRefreshing { tableView.mj_footer.endRefreshing() } @@ -65,7 +66,8 @@ class ContentOptionalViewController: BaseTableViewController, SegementSlideConte } } - @objc private func loadMoreAction() { + @objc + private func loadMoreAction() { guard !tableView.mj_header.isRefreshing else { tableView.mj_footer.endRefreshing() return diff --git a/Example/Main/Content/ContentViewController.swift b/Example/Main/Content/ContentViewController.swift index 4cd5fb4..6ab0cf7 100644 --- a/Example/Main/Content/ContentViewController.swift +++ b/Example/Main/Content/ContentViewController.swift @@ -13,7 +13,8 @@ import MJRefresh class ContentViewController: BaseTableViewController, SegementSlideContentScrollViewDelegate { - @objc var scrollView: UIScrollView { + @objc + var scrollView: UIScrollView { return tableView } @@ -50,7 +51,8 @@ class ContentViewController: BaseTableViewController, SegementSlideContentScroll tableView.mj_header.beginRefreshing() } - @objc private func refreshAction() { + @objc + private func refreshAction() { if tableView.mj_footer.isRefreshing { tableView.mj_footer.endRefreshing() } @@ -68,7 +70,8 @@ class ContentViewController: BaseTableViewController, SegementSlideContentScroll } } - @objc private func loadMoreAction() { + @objc + private func loadMoreAction() { guard !tableView.mj_header.isRefreshing else { tableView.mj_footer.endRefreshing() return diff --git a/Example/Main/Explore/ExploreViewController.swift b/Example/Main/Explore/ExploreViewController.swift index be20f9c..c38e6fe 100644 --- a/Example/Main/Explore/ExploreViewController.swift +++ b/Example/Main/Explore/ExploreViewController.swift @@ -9,7 +9,7 @@ import UIKit import SegementSlide -class ExploreViewController: BaseSegementSlideViewController { +class ExploreViewController: BaseSegementSlideDefaultViewController { private var badges: [Int: BadgeType] = [:] @@ -24,7 +24,7 @@ class ExploreViewController: BaseSegementSlideViewController { fatalError("init(coder:) has not been implemented") } - override var headerView: UIView? { + override func segementSlideHeaderView() -> UIView? { let headerView = UIImageView() headerView.isUserInteractionEnabled = true headerView.contentMode = .scaleAspectFill @@ -34,7 +34,7 @@ class ExploreViewController: BaseSegementSlideViewController { return headerView } - override var switcherConfig: SegementSlideSwitcherConfig { + override var switcherConfig: SegementSlideDefaultSwitcherConfig { var config = super.switcherConfig config.type = .segement return config diff --git a/Example/Main/Home/HomeViewController.swift b/Example/Main/Home/HomeViewController.swift index 4eaa34d..2a2c228 100644 --- a/Example/Main/Home/HomeViewController.swift +++ b/Example/Main/Home/HomeViewController.swift @@ -9,7 +9,7 @@ import UIKit import SegementSlide -class HomeViewController: BaseSegementSlideViewController { +class HomeViewController: BaseSegementSlideDefaultViewController { private var badges: [Int: BadgeType] = [:] @@ -46,7 +46,7 @@ class HomeViewController: BaseSegementSlideViewController { } } - override var switcherConfig: SegementSlideSwitcherConfig { + override var switcherConfig: SegementSlideDefaultSwitcherConfig { var config = super.switcherConfig config.type = .tab return config diff --git a/Example/Main/LanguageCenter/LanguageCenterViewController.swift b/Example/Main/LanguageCenter/LanguageCenterViewController.swift index f0fe196..4eb69eb 100644 --- a/Example/Main/LanguageCenter/LanguageCenterViewController.swift +++ b/Example/Main/LanguageCenter/LanguageCenterViewController.swift @@ -11,7 +11,7 @@ import SegementSlide import MBProgressHUD import MJRefresh -class LanguageCenterViewController: BaseTransparentSlideViewController { +class LanguageCenterViewController: BaseTransparentSlideDefaultViewController { private let id: Int private var badges: [Int: BadgeType] = [:] @@ -43,7 +43,7 @@ class LanguageCenterViewController: BaseTransparentSlideViewController { return .parent } - override var headerView: UIView { + override func segementSlideHeaderView() -> UIView { guard let _ = language else { let view = UIView() view.backgroundColor = .clear @@ -60,7 +60,7 @@ class LanguageCenterViewController: BaseTransparentSlideViewController { return centerHeaderView } - override var switcherConfig: SegementSlideSwitcherConfig { + override var switcherConfig: SegementSlideDefaultSwitcherConfig { var config = super.switcherConfig config.type = .tab return config @@ -90,7 +90,7 @@ class LanguageCenterViewController: BaseTransparentSlideViewController { let viewController = ContentViewController() viewController.refreshHandler = { [weak self] in guard let self = self else { return } - self.slideScrollView.mj_header.endRefreshing() + self.scrollView.mj_header.endRefreshing() self.badges[index] = BadgeType.random self.reloadBadgeInSwitcher() } @@ -105,10 +105,11 @@ class LanguageCenterViewController: BaseTransparentSlideViewController { } else { topLayoutLength = topLayoutGuide.length } - slideScrollView.mj_header.ignoredScrollViewContentInsetTop = -topLayoutLength + scrollView.mj_header.ignoredScrollViewContentInsetTop = -topLayoutLength } - @objc func backAction() { + @objc + func backAction() { dismiss(animated: true, completion: nil) } @@ -127,7 +128,7 @@ class LanguageCenterViewController: BaseTransparentSlideViewController { refreshHeader.setTitle("", for: .pulling) refreshHeader.setTitle("", for: .refreshing) refreshHeader.setTitle("", for: .willRefresh) - slideScrollView.mj_header = refreshHeader + scrollView.mj_header = refreshHeader let hud = MBProgressHUD.showAdded(to: view, animated: true) DispatchQueue.global().asyncAfter(deadline: .now()+Double.random(in: 0..<3)) { DispatchQueue.main.async { [weak self] in @@ -146,9 +147,10 @@ class LanguageCenterViewController: BaseTransparentSlideViewController { } } - @objc private func refreshAction() { + @objc + private func refreshAction() { guard let contentViewController = currentSegementSlideContentViewController as? ContentViewController else { - slideScrollView.mj_header.endRefreshing() + scrollView.mj_header.endRefreshing() return } contentViewController.refresh() diff --git a/Example/Main/Mine/MineViewController.swift b/Example/Main/Mine/MineViewController.swift index c86b82d..651e7ae 100644 --- a/Example/Main/Mine/MineViewController.swift +++ b/Example/Main/Mine/MineViewController.swift @@ -9,7 +9,7 @@ import UIKit import SegementSlide -class MineViewController: BaseTransparentSlideViewController { +class MineViewController: BaseTransparentSlideDefaultViewController { private var badges: [Int: BadgeType] = [:] @@ -35,7 +35,7 @@ class MineViewController: BaseTransparentSlideViewController { return .child } - override var headerView: UIView { + override func segementSlideHeaderView() -> UIView { let headerView = UIImageView() headerView.isUserInteractionEnabled = true headerView.contentMode = .scaleAspectFill @@ -51,7 +51,7 @@ class MineViewController: BaseTransparentSlideViewController { return headerView } - override var switcherConfig: SegementSlideSwitcherConfig { + override var switcherConfig: SegementSlideDefaultSwitcherConfig { var config = super.switcherConfig config.type = .tab return config diff --git a/Example/Main/Notice/NoticeViewController.swift b/Example/Main/Notice/NoticeViewController.swift index ab5ce51..d36d11a 100644 --- a/Example/Main/Notice/NoticeViewController.swift +++ b/Example/Main/Notice/NoticeViewController.swift @@ -12,7 +12,7 @@ import SnapKit class NoticeViewController: UIViewController { - private var segementSlideSwitcherView: SegementSlideSwitcherView! + private var segementSlideSwitcherView: SegementSlideDefaultSwitcherView! private var segementSlideContentView: SegementSlideContentView! private var badges: [Int: BadgeType] = [:] @@ -48,8 +48,8 @@ class NoticeViewController: UIViewController { } private func setupSwitcherView() { - segementSlideSwitcherView = SegementSlideSwitcherView() - segementSlideSwitcherView.config = SegementSlideSwitcherConfig(type: .segement, horizontalMargin: 28) + segementSlideSwitcherView = SegementSlideDefaultSwitcherView() + segementSlideSwitcherView.config = SegementSlideDefaultSwitcherConfig(type: .segement, horizontalMargin: 28) segementSlideSwitcherView.delegate = self let size: CGSize @@ -95,7 +95,8 @@ class NoticeViewController: UIViewController { segementSlideSwitcherView.selectSwitcher(at: index, animated: animated) } - @objc private func moreAction() { + @objc + private func moreAction() { let viewController: UIViewController switch Int.random(in: 0..<8) { case 0..<4: @@ -121,19 +122,19 @@ class NoticeViewController: UIViewController { } -extension NoticeViewController: SegementSlideSwitcherViewDelegate { +extension NoticeViewController: SegementSlideDefaultSwitcherViewDelegate { public var titlesInSegementSlideSwitcherView: [String] { return DataManager.shared.noticeLanguageTitles } - public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideSwitcherView, didSelectAtIndex index: Int, animated: Bool) { + public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, didSelectAtIndex index: Int, animated: Bool) { if segementSlideContentView.selectedIndex != index { segementSlideContentView.scrollToSlide(at: index, animated: animated) } } - public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideSwitcherView, showBadgeAtIndex index: Int) -> BadgeType { + public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, showBadgeAtIndex index: Int) -> BadgeType { if let badge = badges[index] { return badge } else { diff --git a/Example/Main/Post/PostViewController.swift b/Example/Main/Post/PostViewController.swift index 302cf0a..1b2af94 100644 --- a/Example/Main/Post/PostViewController.swift +++ b/Example/Main/Post/PostViewController.swift @@ -9,7 +9,7 @@ import UIKit import SegementSlide -class PostViewController: BaseSegementSlideViewController { +class PostViewController: BaseSegementSlideDefaultViewController { private var badges: [Int: BadgeType] = [:] private let selectedIndex: Int @@ -25,7 +25,7 @@ class PostViewController: BaseSegementSlideViewController { fatalError("init(coder:) has not been implemented") } - override var switcherConfig: SegementSlideSwitcherConfig { + override var switcherConfig: SegementSlideDefaultSwitcherConfig { var config = super.switcherConfig config.type = .tab return config diff --git a/Example/Manager/ConfigManager.swift b/Example/Manager/ConfigManager.swift index b8836f2..d23e8cf 100644 --- a/Example/Manager/ConfigManager.swift +++ b/Example/Manager/ConfigManager.swift @@ -12,9 +12,9 @@ import SegementSlide class ConfigManager { static let shared = ConfigManager() - let switcherConfig: SegementSlideSwitcherConfig + let switcherConfig: SegementSlideDefaultSwitcherConfig init() { - switcherConfig = SegementSlideSwitcherConfig(normalTitleColor: UIColor.gray, selectedTitleColor: UIColor.darkGray, indicatorColor: UIColor.darkGray, badgeHeightForPointType: 9, badgeHeightForCountType: 15, badgeHeightForCustomType: 14) + switcherConfig = SegementSlideDefaultSwitcherConfig(normalTitleColor: UIColor.gray, selectedTitleColor: UIColor.darkGray, indicatorColor: UIColor.darkGray, badgeHeightForPointType: 9, badgeHeightForCountType: 15, badgeHeightForCustomType: 14) } } diff --git a/Example/Util/UINavigationController+Swizzle.swift b/Example/Util/UINavigationController+Swizzle.swift index cacbe22..c497eac 100644 --- a/Example/Util/UINavigationController+Swizzle.swift +++ b/Example/Util/UINavigationController+Swizzle.swift @@ -30,7 +30,8 @@ internal extension UINavigationController { } } - @objc private func newPushViewController(_ viewController: UIViewController, animated: Bool) { + @objc + private func newPushViewController(_ viewController: UIViewController, animated: Bool) { guard viewControllers.count > 0 else { newPushViewController(viewController, animated: animated) return diff --git a/Source/Content/SegementSlideContentView.swift b/Source/Content/SegementSlideContentView.swift index 082324d..1cd5459 100644 --- a/Source/Content/SegementSlideContentView.swift +++ b/Source/Content/SegementSlideContentView.swift @@ -8,7 +8,8 @@ import UIKit -@objc public protocol SegementSlideContentScrollViewDelegate where Self: UIViewController { +@objc +public protocol SegementSlideContentScrollViewDelegate where Self: UIViewController { /// must implement this variable, when use class `SegementSlideViewController` or it's subClass. /// you can ignore this variable, when you use `SegementSlideContentView` alone. @objc optional var scrollView: UIScrollView { get } @@ -24,12 +25,9 @@ public protocol SegementSlideContentDelegate: class { public class SegementSlideContentView: UIView { internal static let willClearAllReusableViewControllersNotification: NSNotification.Name = NSNotification.Name(rawValue: "willClearAllReusableViewControllersNotification") - private let scrollView = UIScrollView() + public private(set) var scrollView = UIScrollView() private var viewControllers: [Int: SegementSlideContentScrollViewDelegate] = [:] private var initSelectedIndex: Int? - internal var gestureRecognizersInScrollView: [UIGestureRecognizer]? { - return scrollView.gestureRecognizers - } public private(set) var selectedIndex: Int? public weak var delegate: SegementSlideContentDelegate? diff --git a/Source/General/SegementSlideDefaultViewController.swift b/Source/General/SegementSlideDefaultViewController.swift new file mode 100644 index 0000000..2eac978 --- /dev/null +++ b/Source/General/SegementSlideDefaultViewController.swift @@ -0,0 +1,76 @@ +// +// SegementSlideDefaultViewController.swift +// SegementSlide +// +// Created by Jiar on 2020/5/6. +// + +import UIKit + +open class SegementSlideDefaultViewController: SegementSlideViewController { + + private let defaultSwitcherView = SegementSlideDefaultSwitcherView() + + public override func segementSlideSwitcherView() -> SegementSlideSwitcherDelegate { + defaultSwitcherView.delegate = self + defaultSwitcherView.dataSource = self + return defaultSwitcherView + } + + internal override func setupSwitcher() { + super.setupSwitcher() + defaultSwitcherView.config = switcherConfig + } + + open var switcherConfig: SegementSlideDefaultSwitcherConfig { + return SegementSlideDefaultSwitcherConfig.shared + } + + open override var switcherHeight: CGFloat { + return 44 + } + + open var titlesInSwitcher: [String] { + return [] + } + + open func showBadgeInSwitcher(at index: Int) -> BadgeType { + return .none + } + + /// reload badges in SwitcherView + public func reloadBadgeInSwitcher() { + defaultSwitcherView.reloadBadges() + } + +} + +extension SegementSlideDefaultViewController: SegementSlideSwitcherDataSource { + + public var height: CGFloat { + return switcherHeight + } + + public var titles: [String] { + return titlesInSwitcher + } + +} + +extension SegementSlideDefaultViewController: SegementSlideDefaultSwitcherViewDelegate { + + public var titlesInSegementSlideSwitcherView: [String] { + return switcherView.dataSource?.titles ?? [] + } + + public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, didSelectAtIndex index: Int, animated: Bool) { + if contentView.selectedIndex != index { + contentView.scrollToSlide(at: index, animated: animated) + } + } + + public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, showBadgeAtIndex index: Int) -> BadgeType { + return showBadgeInSwitcher(at: index) + } + +} diff --git a/Source/General/SegementSlideScrollView.swift b/Source/General/SegementSlideScrollView.swift index fd34197..2365f40 100644 --- a/Source/General/SegementSlideScrollView.swift +++ b/Source/General/SegementSlideScrollView.swift @@ -8,7 +8,7 @@ import UIKit -internal class SegementSlideScrollView: UIScrollView, UIGestureRecognizerDelegate { +public class SegementSlideScrollView: UIScrollView, UIGestureRecognizerDelegate { private var otherGestureRecognizers: [UIGestureRecognizer]? @@ -21,7 +21,7 @@ internal class SegementSlideScrollView: UIScrollView, UIGestureRecognizerDelegat fatalError("init(coder:) has not been implemented") } - internal func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { if let otherGestureRecognizers = otherGestureRecognizers, otherGestureRecognizers.contains(otherGestureRecognizer) { return false } diff --git a/Source/General/SegementSlideViewController+delegate.swift b/Source/General/SegementSlideViewController+delegate.swift index 7cf0346..aa91e64 100644 --- a/Source/General/SegementSlideViewController+delegate.swift +++ b/Source/General/SegementSlideViewController+delegate.swift @@ -23,28 +23,10 @@ extension SegementSlideViewController: UIScrollViewDelegate { } -extension SegementSlideViewController: SegementSlideSwitcherViewDelegate { - - public var titlesInSegementSlideSwitcherView: [String] { - return titlesInSwitcher - } - - public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideSwitcherView, didSelectAtIndex index: Int, animated: Bool) { - if segementSlideContentView.selectedIndex != index { - segementSlideContentView.scrollToSlide(at: index, animated: animated) - } - } - - public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideSwitcherView, showBadgeAtIndex index: Int) -> BadgeType { - return showBadgeInSwitcher(at: index) - } - -} - extension SegementSlideViewController: SegementSlideContentDelegate { public var segementSlideContentScrollViewCount: Int { - return titlesInSwitcher.count + return switcherView.dataSource?.titles.count ?? 0 } public func segementSlideContentScrollView(at index: Int) -> SegementSlideContentScrollViewDelegate? { @@ -53,8 +35,8 @@ extension SegementSlideViewController: SegementSlideContentDelegate { public func segementSlideContentView(_ segementSlideContentView: SegementSlideContentView, didSelectAtIndex index: Int, animated: Bool) { waitTobeResetContentOffsetY.insert(index) - if segementSlideSwitcherView.selectedIndex != index { - segementSlideSwitcherView.selectSwitcher(at: index, animated: animated) + if switcherView.selectedIndex != index { + switcherView.selectSwitcher(at: index, animated: animated) } childKeyValueObservation?.invalidate() guard let childViewController = segementSlideContentView.dequeueReusableViewController(at: index) else { return } diff --git a/Source/General/SegementSlideViewController+scroll.swift b/Source/General/SegementSlideViewController+scroll.swift index 87dda7c..ef3e9ee 100644 --- a/Source/General/SegementSlideViewController+scroll.swift +++ b/Source/General/SegementSlideViewController+scroll.swift @@ -10,45 +10,45 @@ import UIKit extension SegementSlideViewController { - internal func parentScrollViewDidScroll(_ scrollView: UIScrollView) { + internal func parentScrollViewDidScroll(_ parentScrollView: UIScrollView) { defer { - scrollViewDidScroll(scrollView, isParent: true) + scrollViewDidScroll(parentScrollView, isParent: true) } - let parentContentOffsetY = segementSlideScrollView.contentOffset.y + let parentContentOffsetY = scrollView.contentOffset.y switch innerBouncesType { case .parent: if !canParentViewScroll { - segementSlideScrollView.contentOffset.y = headerStickyHeight + scrollView.contentOffset.y = headerStickyHeight canChildViewScroll = true return } else if parentContentOffsetY >= headerStickyHeight { - segementSlideScrollView.contentOffset.y = headerStickyHeight + scrollView.contentOffset.y = headerStickyHeight canParentViewScroll = false canChildViewScroll = true return } case .child: - let childBouncesTranslationY = -scrollView.panGestureRecognizer.translation(in: scrollView).y.rounded(.up) + let childBouncesTranslationY = -parentScrollView.panGestureRecognizer.translation(in: parentScrollView).y.rounded(.up) defer { lastChildBouncesTranslationY = childBouncesTranslationY } if !canParentViewScroll { - segementSlideScrollView.contentOffset.y = headerStickyHeight + scrollView.contentOffset.y = headerStickyHeight canChildViewScroll = true return } else if parentContentOffsetY >= headerStickyHeight { - segementSlideScrollView.contentOffset.y = headerStickyHeight + scrollView.contentOffset.y = headerStickyHeight canParentViewScroll = false canChildViewScroll = true return } else if parentContentOffsetY <= 0 { - segementSlideScrollView.contentOffset.y = 0 + scrollView.contentOffset.y = 0 canChildViewScroll = true } else { guard let childScrollView = currentSegementSlideContentViewController?.scrollView else { return } if childScrollView.contentOffset.y < 0 { if childBouncesTranslationY > lastChildBouncesTranslationY { - segementSlideScrollView.contentOffset.y = 0 + scrollView.contentOffset.y = 0 canChildViewScroll = true } else { canChildViewScroll = false @@ -65,7 +65,7 @@ extension SegementSlideViewController { defer { scrollViewDidScroll(childScrollView, isParent: false) } - let parentContentOffsetY = segementSlideScrollView.contentOffset.y + let parentContentOffsetY = scrollView.contentOffset.y let childContentOffsetY = childScrollView.contentOffset.y switch innerBouncesType { case .parent: diff --git a/Source/General/SegementSlideViewController+setup.swift b/Source/General/SegementSlideViewController+setup.swift index 6645c2d..05e6c97 100644 --- a/Source/General/SegementSlideViewController+setup.swift +++ b/Source/General/SegementSlideViewController+setup.swift @@ -24,52 +24,51 @@ extension SegementSlideViewController { } private func setupSegementSlideViews() { - segementSlideHeaderView = SegementSlideHeaderView() - segementSlideSwitcherView = SegementSlideSwitcherView() - segementSlideContentView = SegementSlideContentView() + headerView = SegementSlideHeaderView() + switcherView = segementSlideSwitcherView() + contentView = SegementSlideContentView() var gestureRecognizers: [UIGestureRecognizer] = [] - if let gestureRecognizersInScrollView = segementSlideSwitcherView.gestureRecognizersInScrollView { + if let gestureRecognizersInScrollView = switcherView.scrollView.gestureRecognizers { gestureRecognizers.append(contentsOf: gestureRecognizersInScrollView) } - if let gestureRecognizersInScrollView = segementSlideContentView.gestureRecognizersInScrollView { + if let gestureRecognizersInScrollView = contentView.scrollView.gestureRecognizers { gestureRecognizers.append(contentsOf: gestureRecognizersInScrollView) } - segementSlideScrollView = SegementSlideScrollView(otherGestureRecognizers: gestureRecognizers) + scrollView = SegementSlideScrollView(otherGestureRecognizers: gestureRecognizers) } private func setupSegementSlideHeaderView() { - segementSlideScrollView.addSubview(segementSlideHeaderView) + scrollView.addSubview(headerView) } private func setupSegementSlideContentView() { - segementSlideContentView.delegate = self - segementSlideContentView.viewController = self - segementSlideScrollView.addSubview(segementSlideContentView) + contentView.delegate = self + contentView.viewController = self + scrollView.addSubview(contentView) } - private func setupSegementSlideSwitcherView() { - segementSlideSwitcherView.delegate = self - segementSlideScrollView.addSubview(segementSlideSwitcherView) + internal func setupSegementSlideSwitcherView() { + scrollView.addSubview(switcherView) } private func setupSegementSlideScrollView() { - view.addSubview(segementSlideScrollView) - segementSlideScrollView.constraintToSuperview() + view.addSubview(scrollView) + scrollView.constraintToSuperview() if #available(iOS 11.0, *) { - segementSlideScrollView.contentInsetAdjustmentBehavior = .never + scrollView.contentInsetAdjustmentBehavior = .never } else { automaticallyAdjustsScrollViewInsets = false } - segementSlideScrollView.backgroundColor = .white - segementSlideScrollView.showsHorizontalScrollIndicator = false - segementSlideScrollView.showsVerticalScrollIndicator = false - segementSlideScrollView.isPagingEnabled = false - segementSlideScrollView.isScrollEnabled = true - segementSlideScrollView.delegate = self + scrollView.backgroundColor = .white + scrollView.showsHorizontalScrollIndicator = false + scrollView.showsVerticalScrollIndicator = false + scrollView.isPagingEnabled = false + scrollView.isScrollEnabled = true + scrollView.delegate = self } private func observeScrollViewContentOffset() { - parentKeyValueObservation = segementSlideScrollView.observe(\.contentOffset, options: [.initial, .new, .old], changeHandler: { [weak self] (scrollView, change) in + parentKeyValueObservation = scrollView.observe(\.contentOffset, options: [.initial, .new, .old], changeHandler: { [weak self] (scrollView, change) in guard let self = self else { return } guard change.newValue != change.oldValue else { return } self.parentScrollViewDidScroll(scrollView) @@ -80,7 +79,8 @@ extension SegementSlideViewController { NotificationCenter.default.addObserver(self, selector: #selector(willClearAllReusableViewControllers(_:)), name: SegementSlideContentView.willClearAllReusableViewControllersNotification, object: nil) } - @objc private func willClearAllReusableViewControllers(_ notification: Notification) { + @objc + private func willClearAllReusableViewControllers(_ notification: Notification) { guard let object = notification.object as? SegementSlideViewController, object === self else { return } @@ -101,11 +101,12 @@ extension SegementSlideViewController { } internal func setupHeader() { - innerHeaderView = headerView + innerHeaderView = segementSlideHeaderView() } + @objc internal func setupSwitcher() { - segementSlideSwitcherView.config = switcherConfig + } internal func layoutSegementSlideScrollView() { @@ -116,83 +117,80 @@ extension SegementSlideViewController { topLayoutLength = self.topLayoutLength } - segementSlideHeaderView.translatesAutoresizingMaskIntoConstraints = false - if segementSlideHeaderView.topConstraint == nil { - segementSlideHeaderView.topConstraint = segementSlideHeaderView.topAnchor.constraint(equalTo: segementSlideScrollView.topAnchor, constant: topLayoutLength) + headerView.translatesAutoresizingMaskIntoConstraints = false + if headerView.topConstraint == nil { + headerView.topConstraint = headerView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: topLayoutLength) } else { - if segementSlideHeaderView.topConstraint?.constant != topLayoutLength { - segementSlideHeaderView.topConstraint?.constant = topLayoutLength + if headerView.topConstraint?.constant != topLayoutLength { + headerView.topConstraint?.constant = topLayoutLength } } - if segementSlideHeaderView.leadingConstraint == nil { - segementSlideHeaderView.leadingConstraint = segementSlideHeaderView.leadingAnchor.constraint(equalTo: view.leadingAnchor) + if headerView.leadingConstraint == nil { + headerView.leadingConstraint = headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor) } - if segementSlideHeaderView.trailingConstraint == nil { - segementSlideHeaderView.trailingConstraint = segementSlideHeaderView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + if headerView.trailingConstraint == nil { + headerView.trailingConstraint = headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor) } - segementSlideHeaderView.config(innerHeaderView, segementSlideContentView: segementSlideContentView) + headerView.config(innerHeaderView, contentView: contentView) - segementSlideSwitcherView.translatesAutoresizingMaskIntoConstraints = false - if segementSlideSwitcherView.topConstraint == nil { - let topConstraint = segementSlideSwitcherView.topAnchor.constraint(equalTo: segementSlideHeaderView.bottomAnchor) + switcherView.translatesAutoresizingMaskIntoConstraints = false + if switcherView.topConstraint == nil { + let topConstraint = switcherView.topAnchor.constraint(equalTo: headerView.bottomAnchor) topConstraint.priority = UILayoutPriority(rawValue: 999) - segementSlideSwitcherView.topConstraint = topConstraint + switcherView.topConstraint = topConstraint } if safeAreaTopConstraint == nil { safeAreaTopConstraint?.isActive = false if #available(iOS 11, *) { - safeAreaTopConstraint = segementSlideSwitcherView.topAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.topAnchor) + safeAreaTopConstraint = switcherView.topAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.topAnchor) } else { - safeAreaTopConstraint = segementSlideSwitcherView.topAnchor.constraint(greaterThanOrEqualTo: topLayoutGuide.bottomAnchor) + safeAreaTopConstraint = switcherView.topAnchor.constraint(greaterThanOrEqualTo: topLayoutGuide.bottomAnchor) } safeAreaTopConstraint?.isActive = true } - if segementSlideSwitcherView.leadingConstraint == nil { - segementSlideSwitcherView.leadingConstraint = segementSlideSwitcherView.leadingAnchor.constraint(equalTo: view.leadingAnchor) + if switcherView.leadingConstraint == nil { + switcherView.leadingConstraint = switcherView.leadingAnchor.constraint(equalTo: view.leadingAnchor) } - if segementSlideSwitcherView.trailingConstraint == nil { - segementSlideSwitcherView.trailingConstraint = segementSlideSwitcherView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + if switcherView.trailingConstraint == nil { + switcherView.trailingConstraint = switcherView.trailingAnchor.constraint(equalTo: view.trailingAnchor) } - if segementSlideSwitcherView.heightConstraint == nil { - segementSlideSwitcherView.heightConstraint = segementSlideSwitcherView.heightAnchor.constraint(equalToConstant: switcherHeight) + if switcherView.heightConstraint == nil { + switcherView.heightConstraint = switcherView.heightAnchor.constraint(equalToConstant: switcherHeight) } else { - if segementSlideSwitcherView.heightConstraint?.constant != switcherHeight { - segementSlideSwitcherView.heightConstraint?.constant = switcherHeight + if switcherView.heightConstraint?.constant != switcherHeight { + switcherView.heightConstraint?.constant = switcherHeight } } - segementSlideContentView.translatesAutoresizingMaskIntoConstraints = false - if segementSlideContentView.topConstraint == nil { - segementSlideContentView.topConstraint = segementSlideContentView.topAnchor.constraint(equalTo: segementSlideSwitcherView.bottomAnchor) + contentView.translatesAutoresizingMaskIntoConstraints = false + if contentView.topConstraint == nil { + contentView.topConstraint = contentView.topAnchor.constraint(equalTo: switcherView.bottomAnchor) } - if segementSlideContentView.leadingConstraint == nil { - segementSlideContentView.leadingConstraint = segementSlideContentView.leadingAnchor.constraint(equalTo: view.leadingAnchor) + if contentView.leadingConstraint == nil { + contentView.leadingConstraint = contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor) } - if segementSlideContentView.trailingConstraint == nil { - segementSlideContentView.trailingConstraint = segementSlideContentView.trailingAnchor.constraint(equalTo: view.trailingAnchor) + if contentView.trailingConstraint == nil { + contentView.trailingConstraint = contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor) } - if segementSlideContentView.bottomConstraint == nil { - segementSlideContentView.bottomConstraint = segementSlideContentView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + if contentView.bottomConstraint == nil { + contentView.bottomConstraint = contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor) } - segementSlideHeaderView.layer.zPosition = -3 - segementSlideContentView.layer.zPosition = -2 - segementSlideSwitcherView.layer.zPosition = -1 + headerView.layer.zPosition = -3 + contentView.layer.zPosition = -2 + switcherView.layer.zPosition = -1 - segementSlideHeaderView.layoutIfNeeded() + headerView.layoutIfNeeded() - let innerHeaderHeight = segementSlideHeaderView.frame.height - let contentSize = CGSize( - width: view.bounds.width, - height: topLayoutLength + innerHeaderHeight + switcherHeight + contentViewHeight + 1 - ) - if segementSlideScrollView.contentSize != contentSize { - segementSlideScrollView.contentSize = contentSize + let innerHeaderHeight = headerView.frame.height + let contentSize = CGSize(width: view.bounds.width, height: topLayoutLength+innerHeaderHeight+switcherHeight+contentViewHeight+1) + if scrollView.contentSize != contentSize { + scrollView.contentSize = contentSize } } internal func resetChildViewControllerContentOffsetY() { - guard segementSlideScrollView.contentOffset.y < headerStickyHeight else { + guard scrollView.contentOffset.y < headerStickyHeight else { return } let collection = waitTobeResetContentOffsetY diff --git a/Source/General/SegementSlideViewController.swift b/Source/General/SegementSlideViewController.swift index 8f04e45..a913426 100644 --- a/Source/General/SegementSlideViewController.swift +++ b/Source/General/SegementSlideViewController.swift @@ -15,10 +15,10 @@ public enum BouncesType { open class SegementSlideViewController: UIViewController { - internal var segementSlideScrollView: SegementSlideScrollView! - internal var segementSlideHeaderView: SegementSlideHeaderView! - internal var segementSlideContentView: SegementSlideContentView! - internal var segementSlideSwitcherView: SegementSlideSwitcherView! + public internal(set) var scrollView: SegementSlideScrollView! + public internal(set) var headerView: SegementSlideHeaderView! + public internal(set) var contentView: SegementSlideContentView! + public internal(set) var switcherView: SegementSlideSwitcherDelegate! internal var innerHeaderView: UIView? internal var safeAreaTopConstraint: NSLayoutConstraint? @@ -30,39 +30,33 @@ open class SegementSlideViewController: UIViewController { internal var lastChildBouncesTranslationY: CGFloat = 0 internal var waitTobeResetContentOffsetY: Set = Set() - public var slideScrollView: UIScrollView { - return segementSlideScrollView - } - public var slideSwitcherView: UIView { - return segementSlideSwitcherView - } - public var slideContentView: UIView { - return segementSlideContentView - } public var headerStickyHeight: CGFloat { - let headerHeight = segementSlideHeaderView.frame.height.rounded(.up) + let headerHeight = headerView.frame.height.rounded(.up) if edgesForExtendedLayout.contains(.top) { return headerHeight - topLayoutLength } else { return headerHeight } } + public var switcherHeight: CGFloat { + return switcherView.dataSource?.height ?? 44 + } public var contentViewHeight: CGFloat { return view.bounds.height-topLayoutLength-switcherHeight } public var currentIndex: Int? { - return segementSlideSwitcherView.selectedIndex + return switcherView.selectedIndex } public var currentSegementSlideContentViewController: SegementSlideContentScrollViewDelegate? { guard let currentIndex = currentIndex else { return nil } - return segementSlideContentView.dequeueReusableViewController(at: currentIndex) + return contentView.dequeueReusableViewController(at: currentIndex) } open var bouncesType: BouncesType { return .parent } - open var headerView: UIView? { + open func segementSlideHeaderView() -> UIView? { if edgesForExtendedLayout.contains(.top) { #if DEBUG assert(false, "must override this variable") @@ -73,23 +67,11 @@ open class SegementSlideViewController: UIViewController { } } - open var switcherHeight: CGFloat { - return 44 - } - - open var switcherConfig: SegementSlideSwitcherConfig { - return SegementSlideSwitcherConfig.shared - } - - open var titlesInSwitcher: [String] { + open func segementSlideSwitcherView() -> SegementSlideSwitcherDelegate { #if DEBUG assert(false, "must override this variable") #endif - return [] - } - - open func showBadgeInSwitcher(at index: Int) -> BadgeType { - return .none + return SegementSlideSwitcherEmptyView() } open func segementSlideContentViewController(at index: Int) -> SegementSlideContentScrollViewDelegate? { @@ -127,8 +109,8 @@ open class SegementSlideViewController: UIViewController { setupHeader() setupSwitcher() waitTobeResetContentOffsetY.removeAll() - segementSlideContentView.reloadData() - segementSlideSwitcherView.reloadData() + contentView.reloadData() + switcherView.reloadData() layoutSegementSlideScrollView() } @@ -141,29 +123,24 @@ open class SegementSlideViewController: UIViewController { /// reload SwitcherView public func reloadSwitcher() { setupSwitcher() - segementSlideSwitcherView.reloadData() + switcherView.reloadData() layoutSegementSlideScrollView() } - /// reload badges in SwitcherView - public func reloadBadgeInSwitcher() { - segementSlideSwitcherView.reloadBadges() - } - /// reload ContentView public func reloadContent() { waitTobeResetContentOffsetY.removeAll() - segementSlideContentView.reloadData() + contentView.reloadData() } /// select one item by index public func scrollToSlide(at index: Int, animated: Bool) { - segementSlideSwitcherView.selectSwitcher(at: index, animated: animated) + switcherView.selectSwitcher(at: index, animated: animated) } /// reuse the `SegementSlideContentScrollViewDelegate` public func dequeueReusableViewController(at index: Int) -> SegementSlideContentScrollViewDelegate? { - return segementSlideContentView.dequeueReusableViewController(at: index) + return contentView.dequeueReusableViewController(at: index) } deinit { diff --git a/Source/General/TransparentSlideDefaultViewController.swift b/Source/General/TransparentSlideDefaultViewController.swift new file mode 100644 index 0000000..bf4296a --- /dev/null +++ b/Source/General/TransparentSlideDefaultViewController.swift @@ -0,0 +1,76 @@ +// +// TransparentSlideDefaultViewController.swift +// SegementSlide +// +// Created by Jiar on 2020/5/6. +// + +import UIKit + +open class TransparentSlideDefaultViewController: TransparentSlideViewController { + + private let defaultSwitcherView = SegementSlideDefaultSwitcherView() + + public override func segementSlideSwitcherView() -> SegementSlideSwitcherDelegate { + defaultSwitcherView.delegate = self + defaultSwitcherView.dataSource = self + return defaultSwitcherView + } + + internal override func setupSwitcher() { + super.setupSwitcher() + defaultSwitcherView.config = switcherConfig + } + + open var switcherConfig: SegementSlideDefaultSwitcherConfig { + return SegementSlideDefaultSwitcherConfig.shared + } + + open override var switcherHeight: CGFloat { + return 44 + } + + open var titlesInSwitcher: [String] { + return [] + } + + open func showBadgeInSwitcher(at index: Int) -> BadgeType { + return .none + } + + /// reload badges in SwitcherView + public func reloadBadgeInSwitcher() { + defaultSwitcherView.reloadBadges() + } + +} + +extension TransparentSlideDefaultViewController: SegementSlideSwitcherDataSource { + + public var height: CGFloat { + return switcherHeight + } + + public var titles: [String] { + return titlesInSwitcher + } + +} + +extension TransparentSlideDefaultViewController: SegementSlideDefaultSwitcherViewDelegate { + + public var titlesInSegementSlideSwitcherView: [String] { + return switcherView.dataSource?.titles ?? [] + } + + public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, didSelectAtIndex index: Int, animated: Bool) { + if contentView.selectedIndex != index { + contentView.scrollToSlide(at: index, animated: animated) + } + } + + public func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, showBadgeAtIndex index: Int) -> BadgeType { + return showBadgeInSwitcher(at: index) + } + +} diff --git a/Source/General/TransparentSlideViewController.swift b/Source/General/TransparentSlideViewController.swift index 8d07529..0024970 100644 --- a/Source/General/TransparentSlideViewController.swift +++ b/Source/General/TransparentSlideViewController.swift @@ -35,7 +35,7 @@ open class TransparentSlideViewController: SegementSlideViewController { public var storedNavigationBarShadowImage: UIImage? = nil public var storedNavigationBarBackgroundImage: UIImage? = nil - open override var headerView: UIView { + open override func segementSlideHeaderView() -> UIView { #if DEBUG assert(false, "must override this variable") #endif diff --git a/Source/Header/SegementSlideHeaderView.swift b/Source/Header/SegementSlideHeaderView.swift index f172f21..3ca9dcd 100644 --- a/Source/Header/SegementSlideHeaderView.swift +++ b/Source/Header/SegementSlideHeaderView.swift @@ -8,10 +8,10 @@ import UIKit -internal class SegementSlideHeaderView: UIView { +public class SegementSlideHeaderView: UIView { private weak var lastHeaderView: UIView? - private weak var segementSlideContentView: SegementSlideContentView? + private weak var contentView: SegementSlideContentView? internal override init(frame: CGRect) { super.init(frame: frame) @@ -27,26 +27,26 @@ internal class SegementSlideHeaderView: UIView { backgroundColor = .clear } - internal func config(_ headerView: UIView?, segementSlideContentView: SegementSlideContentView) { + internal func config(_ headerView: UIView?, contentView: SegementSlideContentView) { guard headerView != lastHeaderView else { return } if let lastHeaderView = lastHeaderView { lastHeaderView.removeAllConstraints() lastHeaderView.removeFromSuperview() } guard let headerView = headerView else { return } - self.segementSlideContentView = segementSlideContentView + self.contentView = contentView addSubview(headerView) headerView.constraintToSuperview() lastHeaderView = headerView } - internal override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let view = super.hitTest(point, with: event) - guard let segementSlideContentView = segementSlideContentView else { + guard let contentView = contentView else { return view } - guard let selectedIndex = segementSlideContentView.selectedIndex, - let segementSlideContentScrollViewDelegate = segementSlideContentView.dequeueReusableViewController(at: selectedIndex) + guard let selectedIndex = contentView.selectedIndex, + let delegate = contentView.dequeueReusableViewController(at: selectedIndex) else { return view } @@ -56,7 +56,7 @@ internal class SegementSlideHeaderView: UIView { if !(view?.gestureRecognizers?.isEmpty ?? true) { return view } - return segementSlideContentScrollViewDelegate.scrollView + return delegate.scrollView } } diff --git a/Source/Badge/BadgeView.swift b/Source/Switcher/BadgeView.swift similarity index 94% rename from Source/Badge/BadgeView.swift rename to Source/Switcher/BadgeView.swift index 1516839..28c4aff 100644 --- a/Source/Badge/BadgeView.swift +++ b/Source/Switcher/BadgeView.swift @@ -24,7 +24,7 @@ public enum BadgeType { private final class BadgeView: UILabel { - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + fileprivate override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if let superview = superview { return superview } else { @@ -36,9 +36,9 @@ private final class BadgeView: UILabel { private var badgeKey: Void? -public extension UIView { +internal extension UIView { - var badge: Badge { + internal var badge: Badge { get { let badge: Badge if let value = objc_getAssociatedObject(self, &badgeKey) as? Badge { @@ -53,7 +53,7 @@ public extension UIView { } -public final class Badge { +internal final class Badge { private let badgeView: BadgeView @@ -76,7 +76,7 @@ public final class Badge { } /// font for the `.count` type - public var font: UIFont = UIFont.systemFont(ofSize: 10, weight: .regular) { + internal var font: UIFont = UIFont.systemFont(ofSize: 10, weight: .regular) { didSet { if case .count = type { badgeView.font = font @@ -85,7 +85,7 @@ public final class Badge { } /// Badge's height, Badge's cornerRadius is half of the value - public var height: CGFloat = 9 { + internal var height: CGFloat = 9 { didSet { updateHeight() } @@ -94,14 +94,14 @@ public final class Badge { /// Badge's center position relative to the parent view's center position displacement /// A positive x means moving to the right /// A positive y means moving to the bottom - public var offset: CGPoint = .zero { + internal var offset: CGPoint = .zero { didSet { remakeConstraints() } } /// the type of `Badge` - public var type: BadgeType = .none { + internal var type: BadgeType = .none { didSet { switch type { case .none, .point: diff --git a/Source/Segement/SegementSlideSwitcherConfig.swift b/Source/Switcher/SegementSlideDefaultSwitcherConfig.swift similarity index 93% rename from Source/Segement/SegementSlideSwitcherConfig.swift rename to Source/Switcher/SegementSlideDefaultSwitcherConfig.swift index 65b5a2d..db9442e 100644 --- a/Source/Segement/SegementSlideSwitcherConfig.swift +++ b/Source/Switcher/SegementSlideDefaultSwitcherConfig.swift @@ -1,5 +1,5 @@ // -// SegementSlideSwitcherConfig.swift +// SegementSlideDefaultSwitcherConfig.swift // SegementSlide // // Created by Jiar on 2019/1/16. @@ -8,9 +8,9 @@ import UIKit -public struct SegementSlideSwitcherConfig { +public struct SegementSlideDefaultSwitcherConfig { - public static let shared = SegementSlideSwitcherConfig() + public static let shared = SegementSlideDefaultSwitcherConfig() public var type: SwitcherType public var horizontalMargin: CGFloat diff --git a/Source/Switcher/SegementSlideDefaultSwitcherView+ex.swift b/Source/Switcher/SegementSlideDefaultSwitcherView+ex.swift new file mode 100644 index 0000000..2ee64a2 --- /dev/null +++ b/Source/Switcher/SegementSlideDefaultSwitcherView+ex.swift @@ -0,0 +1,31 @@ +// +// SegementSlideDefaultSwitcherView+ex.swift +// SegementSlide +// +// Created by Jiar on 2020/5/6. +// + +import UIKit + +final private class WeakBox { + weak var unbox: SegementSlideSwitcherDataSource? + init(_ value: SegementSlideSwitcherDataSource?) { + unbox = value + } +} + +private var dataSourceKey: Void? + +extension SegementSlideDefaultSwitcherView: SegementSlideSwitcherDelegate { + + public weak var dataSource: SegementSlideSwitcherDataSource? { + get { + let weakBox = objc_getAssociatedObject(self, &dataSourceKey) as? WeakBox + return weakBox?.unbox + } + set { + objc_setAssociatedObject(self, &dataSourceKey, WeakBox(newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + +} diff --git a/Source/Segement/SegementSlideSwitcherView.swift b/Source/Switcher/SegementSlideDefaultSwitcherView.swift similarity index 92% rename from Source/Segement/SegementSlideSwitcherView.swift rename to Source/Switcher/SegementSlideDefaultSwitcherView.swift index c23d31d..229d8be 100644 --- a/Source/Segement/SegementSlideSwitcherView.swift +++ b/Source/Switcher/SegementSlideDefaultSwitcherView.swift @@ -1,5 +1,5 @@ // -// SegementSlideSwitcherView.swift +// SegementSlideDefaultSwitcherView.swift // SegementSlide // // Created by Jiar on 2018/12/7. @@ -13,29 +13,26 @@ public enum SwitcherType { case segement } -public protocol SegementSlideSwitcherViewDelegate: class { +public protocol SegementSlideDefaultSwitcherViewDelegate: class { var titlesInSegementSlideSwitcherView: [String] { get } - func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideSwitcherView, didSelectAtIndex index: Int, animated: Bool) - func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideSwitcherView, showBadgeAtIndex index: Int) -> BadgeType + func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, didSelectAtIndex index: Int, animated: Bool) + func segementSwitcherView(_ segementSlideSwitcherView: SegementSlideDefaultSwitcherView, showBadgeAtIndex index: Int) -> BadgeType } -public class SegementSlideSwitcherView: UIView { +public class SegementSlideDefaultSwitcherView: UIView { - private let scrollView = UIScrollView() + public private(set) var scrollView = UIScrollView() private let indicatorView = UIView() private var titleButtons: [UIButton] = [] private var initSelectedIndex: Int? - private var innerConfig: SegementSlideSwitcherConfig = SegementSlideSwitcherConfig.shared - internal var gestureRecognizersInScrollView: [UIGestureRecognizer]? { - return scrollView.gestureRecognizers - } + private var innerConfig: SegementSlideDefaultSwitcherConfig = SegementSlideDefaultSwitcherConfig.shared public private(set) var selectedIndex: Int? - public weak var delegate: SegementSlideSwitcherViewDelegate? + public weak var delegate: SegementSlideDefaultSwitcherViewDelegate? /// you must call `reloadData()` to make it work, after the assignment. - public var config: SegementSlideSwitcherConfig = SegementSlideSwitcherConfig.shared + public var config: SegementSlideDefaultSwitcherConfig = SegementSlideDefaultSwitcherConfig.shared public override var intrinsicContentSize: CGSize { return scrollView.contentSize @@ -153,7 +150,7 @@ public class SegementSlideSwitcherView: UIView { } -extension SegementSlideSwitcherView { +extension SegementSlideDefaultSwitcherView { private func recoverInitSelectedIndex() { guard let initSelectedIndex = initSelectedIndex else { return } @@ -238,7 +235,8 @@ extension SegementSlideSwitcherView { delegate?.segementSwitcherView(self, didSelectAtIndex: index, animated: animated) } - @objc private func didClickTitleButton(_ button: UIButton) { + @objc + private func didClickTitleButton(_ button: UIButton) { selectSwitcher(at: button.tag, animated: true) } diff --git a/Source/Switcher/SegementSlideSwitcherDelegate.swift b/Source/Switcher/SegementSlideSwitcherDelegate.swift new file mode 100644 index 0000000..e4456b4 --- /dev/null +++ b/Source/Switcher/SegementSlideSwitcherDelegate.swift @@ -0,0 +1,42 @@ +// +// SegementSlideSwitcherDelegate.swift +// SegementSlide +// +// Created by Jiar on 2020/5/5. +// + +import UIKit + +public protocol SegementSlideSwitcherDataSource: class { + var height: CGFloat { get } + var titles: [String] { get } +} + +public protocol SegementSlideSwitcherDelegate: UIView { + var dataSource: SegementSlideSwitcherDataSource? { get set } + var scrollView: UIScrollView { get } + var selectedIndex: Int? { get } + + func reloadData() + func reloadBadges() + func selectSwitcher(at index: Int, animated: Bool) +} + +internal final class SegementSlideSwitcherEmptyView: UIView, SegementSlideSwitcherDelegate { + weak var dataSource: SegementSlideSwitcherDataSource? = nil + var scrollView: UIScrollView = UIScrollView() + var selectedIndex: Int? = nil + + func reloadData() { + + } + + func reloadBadges() { + + } + + func selectSwitcher(at index: Int, animated: Bool) { + + } +} + diff --git a/Source/Utility/String+Bounding.swift b/Source/Switcher/String+Bounding.swift similarity index 100% rename from Source/Utility/String+Bounding.swift rename to Source/Switcher/String+Bounding.swift