Commit 1aa6b0a4 authored by jzhang's avatar jzhang

no message

parent e0c176e8
......@@ -40,6 +40,8 @@
697B07ED284F2E5C0051FC23 /* CompleteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 697B07EC284F2E5C0051FC23 /* CompleteVC.swift */; };
6989B7B72852EAB90014BB5B /* wakelock.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6989B7B52852EAA20014BB5B /* wakelock.xcframework */; };
6989B7B82852EAB90014BB5B /* wakelock.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6989B7B52852EAA20014BB5B /* wakelock.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8DE79EDB672D5394BDEB806E /* Pods_BreastFeedingDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39043640BDC7A50986C47129 /* Pods_BreastFeedingDemo.framework */; };
EA14360528E0BF1900FFBE72 /* DemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA14360428E0BF1900FFBE72 /* DemoViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
......@@ -94,6 +96,7 @@
6989B7B52852EAA20014BB5B /* wakelock.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = wakelock.xcframework; sourceTree = "<group>"; };
8C76E81CF245C7C738786086 /* Pods-BreastFeedingDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BreastFeedingDemo.debug.xcconfig"; path = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo.debug.xcconfig"; sourceTree = "<group>"; };
A4415E51DE97A1784932289A /* Pods-BreastFeedingDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BreastFeedingDemo.release.xcconfig"; path = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo.release.xcconfig"; sourceTree = "<group>"; };
EA14360428E0BF1900FFBE72 /* DemoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -113,6 +116,7 @@
694B85EB2848ECF2009BEDE1 /* App.xcframework in Frameworks */,
694B85F92848EDC4009BEDE1 /* FlutterPluginRegistrant.xcframework in Frameworks */,
694B85ED2848ECF4009BEDE1 /* camera.xcframework in Frameworks */,
8DE79EDB672D5394BDEB806E /* Pods_BreastFeedingDemo.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -155,6 +159,7 @@
694B85BB2848EB4C009BEDE1 /* AppDelegate.swift */,
694B85BD2848EB4C009BEDE1 /* SceneDelegate.swift */,
694B85BF2848EB4C009BEDE1 /* ViewController.swift */,
EA14360428E0BF1900FFBE72 /* DemoViewController.swift */,
697B07EC284F2E5C0051FC23 /* CompleteVC.swift */,
692EC419284C81700043E3EA /* ViewModel.swift */,
694B85C12848EB4C009BEDE1 /* Main.storyboard */,
......@@ -213,6 +218,7 @@
694B85B52848EB4C009BEDE1 /* Frameworks */,
694B85B62848EB4C009BEDE1 /* Resources */,
694B85E62848EC8C009BEDE1 /* Embed Frameworks */,
5DA61345C58EE2716C01BA2C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
......@@ -273,6 +279,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
5DA61345C58EE2716C01BA2C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
8AF6361FD6EF23190F10D3B6 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
......@@ -305,6 +328,7 @@
694B85C02848EB4C009BEDE1 /* ViewController.swift in Sources */,
694B85BC2848EB4C009BEDE1 /* AppDelegate.swift in Sources */,
697B07ED284F2E5C0051FC23 /* CompleteVC.swift in Sources */,
EA14360528E0BF1900FFBE72 /* DemoViewController.swift in Sources */,
692EC41A284C81700043E3EA /* ViewModel.swift in Sources */,
694B85BE2848EB4C009BEDE1 /* SceneDelegate.swift in Sources */,
);
......@@ -455,7 +479,10 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = W3C84P5FPS;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = BreastFeedingDemo/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "BF AiDemo";
......@@ -489,7 +516,10 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_TEAM = W3C84P5FPS;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Flutter";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = BreastFeedingDemo/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "BF AiDemo";
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>BreastFeedingDemo.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>BreastFeedingDemo.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
</dict>
</dict>
</plist>
......@@ -436,10 +436,10 @@
</objects>
<point key="canvasLocation" x="-601.44927536231887" y="-227.00892857142856"/>
</scene>
<!--View Controller-->
<!--Demo View Controller-->
<scene sceneID="uUl-lb-yQN">
<objects>
<viewController id="XVX-uo-beN" sceneMemberID="viewController">
<viewController storyboardIdentifier="DemoViewController" id="XVX-uo-beN" customClass="DemoViewController" customModule="BreastFeedingDemo" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="vsR-gb-RGA">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
......@@ -467,6 +467,7 @@
<state key="normal" title="" backgroundImage="icon_global"/>
<connections>
<action selector="showPanel:" destination="BYZ-38-t0r" eventType="touchUpInside" id="uX1-5I-hDE"/>
<action selector="switchLanguageAction:" destination="XVX-uo-beN" eventType="touchUpInside" id="46p-n9-Pdr"/>
</connections>
</button>
</subviews>
......
//
// DemoViewController.swift
// BreastFeedingDemo
//
// Created by jzhang on 2022/9/26.
//
import UIKit
import Popover
import ZJTableViewManager
class DemoViewController: UIViewController {
fileprivate var popover: Popover!
fileprivate var manager: ZJTableViewManager!
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension DemoViewController {
@IBAction func switchLanguageAction(_ sender: UIButton) {
let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 200, height: 135))
// tableView.isScrollEnabled = false
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
} else {
// Fallback on earlier versions
}
manager = ZJTableViewManager(tableView: tableView)
let section = ZJTableViewSection()
manager.add(section: section)
for i in 0...2 {
let item = ZJTableViewItem(text: String(i) + " text text")
section.add(item: item)
}
self.popover = Popover(options: [ .type(.up), .blackOverlayColor(UIColor(white: 0.0, alpha: 0.6))])
self.popover.show(tableView, fromView: sender)
}
}
......@@ -137,6 +137,7 @@ class ViewController: UIViewController {
@IBAction func showPanel(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
popupView.isHidden = !sender.isSelected
//
(panelV.viewWithTag(1000) as! UIButton).isSelected = false
(panelV.viewWithTag(1001) as! UIButton).isSelected = false
(panelV.viewWithTag(1002) as! UIButton).isSelected = false
......
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
source 'https://github.com/CocoaPods/Specs.git'
target 'BreastFeedingDemo' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'ZJTableViewManager', '~> 1.0.8'
pod 'Popover', '~> 1.3.0'
# Pods for BreastFeedingDemo
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
# Pods for BreastFeedingDemo
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1',
]
end
end
end
PODFILE CHECKSUM: 9e3e51b1ff29b93ccce59b38c7b3231538815b9f
PODS:
- Popover (1.3.0)
- ZJTableViewManager (1.0.8):
- ZJTableViewManager/Core (= 1.0.8)
- ZJTableViewManager/Other (= 1.0.8)
- ZJTableViewManager/Core (1.0.8)
- ZJTableViewManager/Other (1.0.8):
- ZJTableViewManager/Core
COCOAPODS: 1.11.3
DEPENDENCIES:
- Popover (~> 1.3.0)
- ZJTableViewManager (~> 1.0.8)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- Popover
- ZJTableViewManager
SPEC CHECKSUMS:
Popover: 10e1d9528f81d9504df984b7b3f491292bc1822d
ZJTableViewManager: 670f0805009b4a2680f20412c9c7be6f41ba7595
PODFILE CHECKSUM: 6a55778ec27acc11a2018147be40d7ee909e78c5
COCOAPODS: 1.11.2
PODFILE CHECKSUM: 9e3e51b1ff29b93ccce59b38c7b3231538815b9f
PODS:
- Popover (1.3.0)
- ZJTableViewManager (1.0.8):
- ZJTableViewManager/Core (= 1.0.8)
- ZJTableViewManager/Other (= 1.0.8)
- ZJTableViewManager/Core (1.0.8)
- ZJTableViewManager/Other (1.0.8):
- ZJTableViewManager/Core
COCOAPODS: 1.11.3
DEPENDENCIES:
- Popover (~> 1.3.0)
- ZJTableViewManager (~> 1.0.8)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- Popover
- ZJTableViewManager
SPEC CHECKSUMS:
Popover: 10e1d9528f81d9504df984b7b3f491292bc1822d
ZJTableViewManager: 670f0805009b4a2680f20412c9c7be6f41ba7595
PODFILE CHECKSUM: 6a55778ec27acc11a2018147be40d7ee909e78c5
COCOAPODS: 1.11.2
......@@ -7,43 +7,155 @@
objects = {
/* Begin PBXBuildFile section */
4AE7460B1C404FB67F49DFCC5CBA8BDE /* Pods-BreastFeedingDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F9E9DDB252B5419FACDF425C3E56A9D8 /* Pods-BreastFeedingDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
E2B7DFBFFEDC68A0D4D24C14B96B3C46 /* Pods-BreastFeedingDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E5BCE493F342DDCA30DC8914CA3311 /* Pods-BreastFeedingDemo-dummy.m */; };
F796724CAC02FA2AF2DFA67E1602C699 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; };
19F8D436ECE585D420E30B3D464A7339 /* ZJTableViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5D04D844D9B6ADA7C7FB3C0A9D48761 /* ZJTableViewItem.swift */; };
50968D0C5AA944A777535F6E8C758FBD /* ZJTableViewManager-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 60137F1603FB9AFBAECC15CDBE791657 /* ZJTableViewManager-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
59226B73389AC742CC399C84C9B984E2 /* ZJProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5616737D3ED58E111CA1B93AB4C6CC2A /* ZJProtocol.swift */; };
6F7CB932BD20A01C26325651C7995725 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; };
7860FA2DFD21A7AC9966CC48EA4AEA12 /* Popover.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33BCB546090A21A165464E36EA63E0B /* Popover.swift */; };
99470FAAC710C90198626270C4C8633F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; };
A0A5A2FB43F9E76E0C30C2BA93AEA5B2 /* ZJExpandTreeCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDE5AEBF6D58E0A48C1BD664290D195 /* ZJExpandTreeCellItem.swift */; };
A2D783F95AF9CAD09F2B278C22CC2BB3 /* ZJTableViewManager-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7536A91AA4935687489C51D67C875781 /* ZJTableViewManager-dummy.m */; };
A454FDE721C693A7455E425F500973B1 /* Popover-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CAA970AAC11ABA920E1A511D765BF9FA /* Popover-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
AEA75FB1504FD18971565D28E7734600 /* Pods-BreastFeedingDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8669227266088AAD1B7292780A65F6C6 /* Pods-BreastFeedingDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
BF71DA50130FF7925BC8E53CB51022CC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; };
C016403C62A6AC02ACA9D2D5463815BE /* Pods-BreastFeedingDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D83C89E46066FB3243BAB31441C909 /* Pods-BreastFeedingDemo-dummy.m */; };
CA1A83D7E36AAA68CA7D60964371B075 /* Popover-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 710EB20C935508FE54891378D15F2A4D /* Popover-dummy.m */; };
CB05E4BC2B9338C16ACCC1EE21805D53 /* ZJTableViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296EF36B85A894A60EE81DBFB98FBE7 /* ZJTableViewManager.swift */; };
DF21B940E324C200E6F2FEC87F1F3A94 /* ZJTableViewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 688B6E90BBEB6C3840E5607EA0C2B0E1 /* ZJTableViewSection.swift */; };
FA66E6E73050716F760CA2A53A21316E /* ZJDefaultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96FFD80C6A2B03BCE8F82D00022870CF /* ZJDefaultCell.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
6CF2DB9F83088532B314D2C6B209D805 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F366DD389362A47A0707FE45D5503886;
remoteInfo = ZJTableViewManager;
};
DF3525CB539C59B991A65E7287C1E69E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 89ADB0D61D0BE9648E9853F5F8BDA717;
remoteInfo = Popover;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0BC1DC472EB417AC3509AF249B5E0453 /* ZJTableViewManager.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ZJTableViewManager.release.xcconfig; sourceTree = "<group>"; };
10DD7736AF333FDD8D4473F7CDCFC87D /* Pods-BreastFeedingDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BreastFeedingDemo-Info.plist"; sourceTree = "<group>"; };
134C52C599B8DC66E4F472335AEDC479 /* Pods-BreastFeedingDemo */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-BreastFeedingDemo"; path = Pods_BreastFeedingDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29D0082F20B88FFDB1BA075C934F43A2 /* Pods-BreastFeedingDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BreastFeedingDemo-Info.plist"; sourceTree = "<group>"; };
45C16A58D0B58329CF02DC89987E9CB9 /* Pods-BreastFeedingDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BreastFeedingDemo-acknowledgements.plist"; sourceTree = "<group>"; };
6A25D58E9B7485906D723F49F4E4C349 /* Pods-BreastFeedingDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BreastFeedingDemo.debug.xcconfig"; sourceTree = "<group>"; };
6F25050C1F92EDA720CA5CE5B7AB302C /* Pods-BreastFeedingDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-BreastFeedingDemo-acknowledgements.markdown"; sourceTree = "<group>"; };
16D579916A50B78B163B61F740CB19B9 /* Pods-BreastFeedingDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-BreastFeedingDemo.modulemap"; sourceTree = "<group>"; };
1DDE5AEBF6D58E0A48C1BD664290D195 /* ZJExpandTreeCellItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZJExpandTreeCellItem.swift; path = ZJTableViewManager/Other/ZJExpandTreeCellItem.swift; sourceTree = "<group>"; };
29A42C062AD3D8788EE4B920B3B47358 /* Pods-BreastFeedingDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BreastFeedingDemo.release.xcconfig"; sourceTree = "<group>"; };
370EDD0BA4D1DBFA7D1957F45C7FBC24 /* ZJTableViewManager.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ZJTableViewManager.debug.xcconfig; sourceTree = "<group>"; };
41BAD1C23B351EDCECA15FFFB3706BB6 /* Popover.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Popover.release.xcconfig; sourceTree = "<group>"; };
4296EF36B85A894A60EE81DBFB98FBE7 /* ZJTableViewManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZJTableViewManager.swift; path = ZJTableViewManager/Core/ZJTableViewManager.swift; sourceTree = "<group>"; };
5358F9AE8183B7EB6595CCF771F892BE /* ZJTableViewManager-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ZJTableViewManager-prefix.pch"; sourceTree = "<group>"; };
5616737D3ED58E111CA1B93AB4C6CC2A /* ZJProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZJProtocol.swift; path = ZJTableViewManager/Core/ZJProtocol.swift; sourceTree = "<group>"; };
56E053A96D2E034079AC4383CD84FCFB /* Popover-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Popover-Info.plist"; sourceTree = "<group>"; };
5AB9E77538524898FA243D4AD3D228C4 /* Popover.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Popover.debug.xcconfig; sourceTree = "<group>"; };
60137F1603FB9AFBAECC15CDBE791657 /* ZJTableViewManager-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ZJTableViewManager-umbrella.h"; sourceTree = "<group>"; };
6471F0E3CD3708E8C00778717A81BF66 /* ZJTableViewManager */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = ZJTableViewManager; path = ZJTableViewManager.framework; sourceTree = BUILT_PRODUCTS_DIR; };
688B6E90BBEB6C3840E5607EA0C2B0E1 /* ZJTableViewSection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZJTableViewSection.swift; path = ZJTableViewManager/Core/ZJTableViewSection.swift; sourceTree = "<group>"; };
6F5665DB399CDAC0DCF6C6AB6047C138 /* Pods-BreastFeedingDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-BreastFeedingDemo-acknowledgements.markdown"; sourceTree = "<group>"; };
710EB20C935508FE54891378D15F2A4D /* Popover-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Popover-dummy.m"; sourceTree = "<group>"; };
73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
97E5BCE493F342DDCA30DC8914CA3311 /* Pods-BreastFeedingDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-BreastFeedingDemo-dummy.m"; sourceTree = "<group>"; };
7536A91AA4935687489C51D67C875781 /* ZJTableViewManager-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ZJTableViewManager-dummy.m"; sourceTree = "<group>"; };
7D08EE56BAE631F60F2B9D7F988CDAB5 /* Popover-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Popover-prefix.pch"; sourceTree = "<group>"; };
8669227266088AAD1B7292780A65F6C6 /* Pods-BreastFeedingDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-BreastFeedingDemo-umbrella.h"; sourceTree = "<group>"; };
8FED0B46C7C100F3B9B92C70B8D79E4E /* Popover.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Popover.modulemap; sourceTree = "<group>"; };
93833EDDB1450F1F8199940CF64275A1 /* Pods-BreastFeedingDemo-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-BreastFeedingDemo-frameworks.sh"; sourceTree = "<group>"; };
96D83C89E46066FB3243BAB31441C909 /* Pods-BreastFeedingDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-BreastFeedingDemo-dummy.m"; sourceTree = "<group>"; };
96FFD80C6A2B03BCE8F82D00022870CF /* ZJDefaultCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZJDefaultCell.swift; path = ZJTableViewManager/Core/ZJDefaultCell.swift; sourceTree = "<group>"; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
C2A216A2CF978F48F907B388798DCF06 /* Pods-BreastFeedingDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-BreastFeedingDemo.modulemap"; sourceTree = "<group>"; };
E2921D1C1E48B4F5265B95E24C6EC105 /* Pods-BreastFeedingDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BreastFeedingDemo.release.xcconfig"; sourceTree = "<group>"; };
F9E9DDB252B5419FACDF425C3E56A9D8 /* Pods-BreastFeedingDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-BreastFeedingDemo-umbrella.h"; sourceTree = "<group>"; };
B72A389B0E6A6DD2F3D61F4DC7F84D83 /* Popover */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Popover; path = Popover.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CAA970AAC11ABA920E1A511D765BF9FA /* Popover-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Popover-umbrella.h"; sourceTree = "<group>"; };
DA953EF94FA5BA35040AE1ADF9B32442 /* ZJTableViewManager.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = ZJTableViewManager.modulemap; sourceTree = "<group>"; };
E5766C029525F2B97A6E67B8FFFCB9C7 /* Pods-BreastFeedingDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BreastFeedingDemo.debug.xcconfig"; sourceTree = "<group>"; };
E5D04D844D9B6ADA7C7FB3C0A9D48761 /* ZJTableViewItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZJTableViewItem.swift; path = ZJTableViewManager/Core/ZJTableViewItem.swift; sourceTree = "<group>"; };
E7914853362D9BC9B6A4DCD3EA0B9F06 /* ZJTableViewManager-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ZJTableViewManager-Info.plist"; sourceTree = "<group>"; };
EED35B2BED30227694003D072877C5C5 /* Pods-BreastFeedingDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BreastFeedingDemo-acknowledgements.plist"; sourceTree = "<group>"; };
F33BCB546090A21A165464E36EA63E0B /* Popover.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Popover.swift; path = Classes/Popover.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
6BD869EA6CEA2DCB6BDDCAC05FA68476 /* Frameworks */ = {
684A7061972DBB8F3700AAA42C1138DA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BF71DA50130FF7925BC8E53CB51022CC /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8DBE49CD76D977D13ED67C2ED4A3BEAC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
99470FAAC710C90198626270C4C8633F /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
AC7C854E4B821FFBD025829200D41F4A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F796724CAC02FA2AF2DFA67E1602C699 /* Foundation.framework in Frameworks */,
6F7CB932BD20A01C26325651C7995725 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
45AE023C8A621AE6F91FB073EB2D8329 /* Products */ = {
049AAE4553E08049961A271DD483C6ED /* Core */ = {
isa = PBXGroup;
children = (
134C52C599B8DC66E4F472335AEDC479 /* Pods-BreastFeedingDemo */,
96FFD80C6A2B03BCE8F82D00022870CF /* ZJDefaultCell.swift */,
5616737D3ED58E111CA1B93AB4C6CC2A /* ZJProtocol.swift */,
E5D04D844D9B6ADA7C7FB3C0A9D48761 /* ZJTableViewItem.swift */,
4296EF36B85A894A60EE81DBFB98FBE7 /* ZJTableViewManager.swift */,
688B6E90BBEB6C3840E5607EA0C2B0E1 /* ZJTableViewSection.swift */,
);
name = Products;
name = Core;
sourceTree = "<group>";
};
12B40B9DFB17900C665BD18A9C865B66 /* Pods-BreastFeedingDemo */ = {
isa = PBXGroup;
children = (
16D579916A50B78B163B61F740CB19B9 /* Pods-BreastFeedingDemo.modulemap */,
6F5665DB399CDAC0DCF6C6AB6047C138 /* Pods-BreastFeedingDemo-acknowledgements.markdown */,
EED35B2BED30227694003D072877C5C5 /* Pods-BreastFeedingDemo-acknowledgements.plist */,
96D83C89E46066FB3243BAB31441C909 /* Pods-BreastFeedingDemo-dummy.m */,
93833EDDB1450F1F8199940CF64275A1 /* Pods-BreastFeedingDemo-frameworks.sh */,
10DD7736AF333FDD8D4473F7CDCFC87D /* Pods-BreastFeedingDemo-Info.plist */,
8669227266088AAD1B7292780A65F6C6 /* Pods-BreastFeedingDemo-umbrella.h */,
E5766C029525F2B97A6E67B8FFFCB9C7 /* Pods-BreastFeedingDemo.debug.xcconfig */,
29A42C062AD3D8788EE4B920B3B47358 /* Pods-BreastFeedingDemo.release.xcconfig */,
);
name = "Pods-BreastFeedingDemo";
path = "Target Support Files/Pods-BreastFeedingDemo";
sourceTree = "<group>";
};
20A5B1B1D38D316B59738CE4750CE626 /* Popover */ = {
isa = PBXGroup;
children = (
F33BCB546090A21A165464E36EA63E0B /* Popover.swift */,
99094AB316CEE6F1D8E2C32E935620F2 /* Support Files */,
);
name = Popover;
path = Popover;
sourceTree = "<group>";
};
4CAFD81C5D07F38ED1CAD4FD033BE621 /* ZJTableViewManager */ = {
isa = PBXGroup;
children = (
049AAE4553E08049961A271DD483C6ED /* Core */,
E7C00D2717A04106E2269CE066C2E97A /* Other */,
B38E3B2D5D2AD0F49ECC86AF3FE028A9 /* Support Files */,
);
name = ZJTableViewManager;
path = ZJTableViewManager;
sourceTree = "<group>";
};
578452D2E740E91742655AC8F1636D1F /* iOS */ = {
......@@ -54,28 +166,53 @@
name = iOS;
sourceTree = "<group>";
};
6E18D0AFDDB4ACE88460407660300CFB /* Pods-BreastFeedingDemo */ = {
7DAA47C158D83B2327EDDB59BC7DCCAF /* Pods */ = {
isa = PBXGroup;
children = (
C2A216A2CF978F48F907B388798DCF06 /* Pods-BreastFeedingDemo.modulemap */,
6F25050C1F92EDA720CA5CE5B7AB302C /* Pods-BreastFeedingDemo-acknowledgements.markdown */,
45C16A58D0B58329CF02DC89987E9CB9 /* Pods-BreastFeedingDemo-acknowledgements.plist */,
97E5BCE493F342DDCA30DC8914CA3311 /* Pods-BreastFeedingDemo-dummy.m */,
29D0082F20B88FFDB1BA075C934F43A2 /* Pods-BreastFeedingDemo-Info.plist */,
F9E9DDB252B5419FACDF425C3E56A9D8 /* Pods-BreastFeedingDemo-umbrella.h */,
6A25D58E9B7485906D723F49F4E4C349 /* Pods-BreastFeedingDemo.debug.xcconfig */,
E2921D1C1E48B4F5265B95E24C6EC105 /* Pods-BreastFeedingDemo.release.xcconfig */,
20A5B1B1D38D316B59738CE4750CE626 /* Popover */,
4CAFD81C5D07F38ED1CAD4FD033BE621 /* ZJTableViewManager */,
);
name = "Pods-BreastFeedingDemo";
path = "Target Support Files/Pods-BreastFeedingDemo";
name = Pods;
sourceTree = "<group>";
};
AAF8769BB938B39C2AD5EE839F287895 /* Targets Support Files */ = {
99094AB316CEE6F1D8E2C32E935620F2 /* Support Files */ = {
isa = PBXGroup;
children = (
6E18D0AFDDB4ACE88460407660300CFB /* Pods-BreastFeedingDemo */,
8FED0B46C7C100F3B9B92C70B8D79E4E /* Popover.modulemap */,
710EB20C935508FE54891378D15F2A4D /* Popover-dummy.m */,
56E053A96D2E034079AC4383CD84FCFB /* Popover-Info.plist */,
7D08EE56BAE631F60F2B9D7F988CDAB5 /* Popover-prefix.pch */,
CAA970AAC11ABA920E1A511D765BF9FA /* Popover-umbrella.h */,
5AB9E77538524898FA243D4AD3D228C4 /* Popover.debug.xcconfig */,
41BAD1C23B351EDCECA15FFFB3706BB6 /* Popover.release.xcconfig */,
);
name = "Targets Support Files";
name = "Support Files";
path = "../Target Support Files/Popover";
sourceTree = "<group>";
};
A9DD64D337AEA6D283F1317BB2683248 /* Products */ = {
isa = PBXGroup;
children = (
134C52C599B8DC66E4F472335AEDC479 /* Pods-BreastFeedingDemo */,
B72A389B0E6A6DD2F3D61F4DC7F84D83 /* Popover */,
6471F0E3CD3708E8C00778717A81BF66 /* ZJTableViewManager */,
);
name = Products;
sourceTree = "<group>";
};
B38E3B2D5D2AD0F49ECC86AF3FE028A9 /* Support Files */ = {
isa = PBXGroup;
children = (
DA953EF94FA5BA35040AE1ADF9B32442 /* ZJTableViewManager.modulemap */,
7536A91AA4935687489C51D67C875781 /* ZJTableViewManager-dummy.m */,
E7914853362D9BC9B6A4DCD3EA0B9F06 /* ZJTableViewManager-Info.plist */,
5358F9AE8183B7EB6595CCF771F892BE /* ZJTableViewManager-prefix.pch */,
60137F1603FB9AFBAECC15CDBE791657 /* ZJTableViewManager-umbrella.h */,
370EDD0BA4D1DBFA7D1957F45C7FBC24 /* ZJTableViewManager.debug.xcconfig */,
0BC1DC472EB417AC3509AF249B5E0453 /* ZJTableViewManager.release.xcconfig */,
);
name = "Support Files";
path = "../Target Support Files/ZJTableViewManager";
sourceTree = "<group>";
};
CF1408CF629C7361332E53B88F7BD30C = {
......@@ -83,8 +220,9 @@
children = (
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */,
D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */,
45AE023C8A621AE6F91FB073EB2D8329 /* Products */,
AAF8769BB938B39C2AD5EE839F287895 /* Targets Support Files */,
7DAA47C158D83B2327EDDB59BC7DCCAF /* Pods */,
A9DD64D337AEA6D283F1317BB2683248 /* Products */,
E8CEBAD4D2A41275633E5B8CA4D6FCD0 /* Targets Support Files */,
);
sourceTree = "<group>";
};
......@@ -96,38 +234,108 @@
name = Frameworks;
sourceTree = "<group>";
};
E7C00D2717A04106E2269CE066C2E97A /* Other */ = {
isa = PBXGroup;
children = (
1DDE5AEBF6D58E0A48C1BD664290D195 /* ZJExpandTreeCellItem.swift */,
);
name = Other;
sourceTree = "<group>";
};
E8CEBAD4D2A41275633E5B8CA4D6FCD0 /* Targets Support Files */ = {
isa = PBXGroup;
children = (
12B40B9DFB17900C665BD18A9C865B66 /* Pods-BreastFeedingDemo */,
);
name = "Targets Support Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
3B9B53BCC5A8458590D37EF887A99557 /* Headers */ = {
4D91606A98E3D48B4882EE0224EC7097 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
4AE7460B1C404FB67F49DFCC5CBA8BDE /* Pods-BreastFeedingDemo-umbrella.h in Headers */,
50968D0C5AA944A777535F6E8C758FBD /* ZJTableViewManager-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7E14BF9B53FE33B5739898C1F45D414B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
A454FDE721C693A7455E425F500973B1 /* Popover-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
86EEA7E809B4B0B9BBDC6731483D6C4F /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
AEA75FB1504FD18971565D28E7734600 /* Pods-BreastFeedingDemo-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
89ADB0D61D0BE9648E9853F5F8BDA717 /* Popover */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13A3C4471CADE0420F8ED9C07C700C48 /* Build configuration list for PBXNativeTarget "Popover" */;
buildPhases = (
7E14BF9B53FE33B5739898C1F45D414B /* Headers */,
A53CC1FC6F2B27375D35087BE1A7FB24 /* Sources */,
AC7C854E4B821FFBD025829200D41F4A /* Frameworks */,
0C37D8CC78066139CEAC63D4BB605A0F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Popover;
productName = Popover;
productReference = B72A389B0E6A6DD2F3D61F4DC7F84D83 /* Popover */;
productType = "com.apple.product-type.framework";
};
B5C990C062A5766D35C8D9B8A6A9B6D2 /* Pods-BreastFeedingDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 601A9A8C7F6DF07ED30B4D1D36EDECB3 /* Build configuration list for PBXNativeTarget "Pods-BreastFeedingDemo" */;
buildConfigurationList = F6FA406264AE7C05EFF7D895FCD50AE7 /* Build configuration list for PBXNativeTarget "Pods-BreastFeedingDemo" */;
buildPhases = (
3B9B53BCC5A8458590D37EF887A99557 /* Headers */,
446206A1AD49B8B11CDB23E07962F10D /* Sources */,
6BD869EA6CEA2DCB6BDDCAC05FA68476 /* Frameworks */,
BBD0A053BAC8C197F8568B62B26C6051 /* Resources */,
86EEA7E809B4B0B9BBDC6731483D6C4F /* Headers */,
53D9BD4A9A82B4BDA15A3430F8CC20E5 /* Sources */,
8DBE49CD76D977D13ED67C2ED4A3BEAC /* Frameworks */,
B323571974B3DB26D9FF0BE7576678D4 /* Resources */,
);
buildRules = (
);
dependencies = (
0E2D62565B5ACCFD28621414A86D6136 /* PBXTargetDependency */,
67EE8D4B5803822E3EAFE224AE91DEE4 /* PBXTargetDependency */,
);
name = "Pods-BreastFeedingDemo";
productName = Pods_BreastFeedingDemo;
productReference = 134C52C599B8DC66E4F472335AEDC479 /* Pods-BreastFeedingDemo */;
productType = "com.apple.product-type.framework";
};
F366DD389362A47A0707FE45D5503886 /* ZJTableViewManager */ = {
isa = PBXNativeTarget;
buildConfigurationList = 711CFE090C36D5D7769933BAAAF6463F /* Build configuration list for PBXNativeTarget "ZJTableViewManager" */;
buildPhases = (
4D91606A98E3D48B4882EE0224EC7097 /* Headers */,
55576056B7C78305A1C1AFCCDE0E2D5C /* Sources */,
684A7061972DBB8F3700AAA42C1138DA /* Frameworks */,
BD7BD937390F1FD85389119BF0BDA860 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = ZJTableViewManager;
productName = ZJTableViewManager;
productReference = 6471F0E3CD3708E8C00778717A81BF66 /* ZJTableViewManager */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
......@@ -146,17 +354,33 @@
en,
);
mainGroup = CF1408CF629C7361332E53B88F7BD30C;
productRefGroup = 45AE023C8A621AE6F91FB073EB2D8329 /* Products */;
productRefGroup = A9DD64D337AEA6D283F1317BB2683248 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
B5C990C062A5766D35C8D9B8A6A9B6D2 /* Pods-BreastFeedingDemo */,
89ADB0D61D0BE9648E9853F5F8BDA717 /* Popover */,
F366DD389362A47A0707FE45D5503886 /* ZJTableViewManager */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
BBD0A053BAC8C197F8568B62B26C6051 /* Resources */ = {
0C37D8CC78066139CEAC63D4BB605A0F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
B323571974B3DB26D9FF0BE7576678D4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
BD7BD937390F1FD85389119BF0BDA860 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
......@@ -166,23 +390,59 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
446206A1AD49B8B11CDB23E07962F10D /* Sources */ = {
53D9BD4A9A82B4BDA15A3430F8CC20E5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2B7DFBFFEDC68A0D4D24C14B96B3C46 /* Pods-BreastFeedingDemo-dummy.m in Sources */,
C016403C62A6AC02ACA9D2D5463815BE /* Pods-BreastFeedingDemo-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
55576056B7C78305A1C1AFCCDE0E2D5C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FA66E6E73050716F760CA2A53A21316E /* ZJDefaultCell.swift in Sources */,
A0A5A2FB43F9E76E0C30C2BA93AEA5B2 /* ZJExpandTreeCellItem.swift in Sources */,
59226B73389AC742CC399C84C9B984E2 /* ZJProtocol.swift in Sources */,
19F8D436ECE585D420E30B3D464A7339 /* ZJTableViewItem.swift in Sources */,
CB05E4BC2B9338C16ACCC1EE21805D53 /* ZJTableViewManager.swift in Sources */,
A2D783F95AF9CAD09F2B278C22CC2BB3 /* ZJTableViewManager-dummy.m in Sources */,
DF21B940E324C200E6F2FEC87F1F3A94 /* ZJTableViewSection.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A53CC1FC6F2B27375D35087BE1A7FB24 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7860FA2DFD21A7AC9966CC48EA4AEA12 /* Popover.swift in Sources */,
CA1A83D7E36AAA68CA7D60964371B075 /* Popover-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
0E2D62565B5ACCFD28621414A86D6136 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Popover;
target = 89ADB0D61D0BE9648E9853F5F8BDA717 /* Popover */;
targetProxy = DF3525CB539C59B991A65E7287C1E69E /* PBXContainerItemProxy */;
};
67EE8D4B5803822E3EAFE224AE91DEE4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = ZJTableViewManager;
target = F366DD389362A47A0707FE45D5503886 /* ZJTableViewManager */;
targetProxy = 6CF2DB9F83088532B314D2C6B209D805 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
323F42244276891C9319F3B08480FD7E /* Release */ = {
74EE4C3DDBFA63E05A71C3141F568788 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E2921D1C1E48B4F5265B95E24C6EC105 /* Pods-BreastFeedingDemo.release.xcconfig */;
baseConfigurationReference = 41BAD1C23B351EDCECA15FFFB3706BB6 /* Popover.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
......@@ -191,27 +451,57 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
GCC_PREFIX_HEADER = "Target Support Files/Popover/Popover-prefix.pch";
INFOPLIST_FILE = "Target Support Files/Popover/Popover-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"PERMISSION_CAMERA=1",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
INFOPLIST_FILE = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-Info.plist";
MODULEMAP_FILE = "Target Support Files/Popover/Popover.modulemap";
PRODUCT_MODULE_NAME = Popover;
PRODUCT_NAME = Popover;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.1;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
82B54D90228F940D928955B8F3AA8AA2 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0BC1DC472EB417AC3509AF249B5E0453 /* ZJTableViewManager.release.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Target Support Files/ZJTableViewManager/ZJTableViewManager-prefix.pch";
INFOPLIST_FILE = "Target Support Files/ZJTableViewManager/ZJTableViewManager-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
MODULEMAP_FILE = "Target Support Files/ZJTableViewManager/ZJTableViewManager.modulemap";
PRODUCT_MODULE_NAME = ZJTableViewManager;
PRODUCT_NAME = ZJTableViewManager;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.2;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
......@@ -347,9 +637,43 @@
};
name = Release;
};
E7AC711BE12D19DF30F823823AEF08BA /* Debug */ = {
BC8A37680771BFB16ACC8D8F3A448D92 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 370EDD0BA4D1DBFA7D1957F45C7FBC24 /* ZJTableViewManager.debug.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Target Support Files/ZJTableViewManager/ZJTableViewManager-prefix.pch";
INFOPLIST_FILE = "Target Support Files/ZJTableViewManager/ZJTableViewManager-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MODULEMAP_FILE = "Target Support Files/ZJTableViewManager/ZJTableViewManager.modulemap";
PRODUCT_MODULE_NAME = ZJTableViewManager;
PRODUCT_NAME = ZJTableViewManager;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.2;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
C1BBCFB003C2A36F869D6B2363392459 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6A25D58E9B7485906D723F49F4E4C349 /* Pods-BreastFeedingDemo.debug.xcconfig */;
baseConfigurationReference = E5766C029525F2B97A6E67B8FFFCB9C7 /* Pods-BreastFeedingDemo.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
......@@ -361,10 +685,77 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
INFOPLIST_FILE = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
C7B32E906567C873279F810F540EE593 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5AB9E77538524898FA243D4AD3D228C4 /* Popover.debug.xcconfig */;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Target Support Files/Popover/Popover-prefix.pch";
INFOPLIST_FILE = "Target Support Files/Popover/Popover-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"PERMISSION_CAMERA=1",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MODULEMAP_FILE = "Target Support Files/Popover/Popover.modulemap";
PRODUCT_MODULE_NAME = Popover;
PRODUCT_NAME = Popover;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
SWIFT_VERSION = 5.1;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
D35FCC27369D6ABFA1D3B89BA296E7E9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 29A42C062AD3D8788EE4B920B3B47358 /* Pods-BreastFeedingDemo.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
......@@ -383,14 +774,24 @@
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
13A3C4471CADE0420F8ED9C07C700C48 /* Build configuration list for PBXNativeTarget "Popover" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C7B32E906567C873279F810F540EE593 /* Debug */,
74EE4C3DDBFA63E05A71C3141F568788 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = {
isa = XCConfigurationList;
buildConfigurations = (
......@@ -400,11 +801,20 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
601A9A8C7F6DF07ED30B4D1D36EDECB3 /* Build configuration list for PBXNativeTarget "Pods-BreastFeedingDemo" */ = {
711CFE090C36D5D7769933BAAAF6463F /* Build configuration list for PBXNativeTarget "ZJTableViewManager" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BC8A37680771BFB16ACC8D8F3A448D92 /* Debug */,
82B54D90228F940D928955B8F3AA8AA2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F6FA406264AE7C05EFF7D895FCD50AE7 /* Build configuration list for PBXNativeTarget "Pods-BreastFeedingDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E7AC711BE12D19DF30F823823AEF08BA /* Debug */,
323F42244276891C9319F3B08480FD7E /* Release */,
C1BBCFB003C2A36F869D6B2363392459 /* Debug */,
D35FCC27369D6ABFA1D3B89BA296E7E9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Pods-BreastFeedingDemo.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B5C990C062A5766D35C8D9B8A6A9B6D2"
BuildableName = "Pods_BreastFeedingDemo.framework"
BlueprintName = "Pods-BreastFeedingDemo"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "89ADB0D61D0BE9648E9853F5F8BDA717"
BuildableName = "Popover.framework"
BlueprintName = "Popover"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F366DD389362A47A0707FE45D5503886"
BuildableName = "ZJTableViewManager.framework"
BlueprintName = "ZJTableViewManager"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Pods-BreastFeedingDemo.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>Popover.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>ZJTableViewManager.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict/>
</dict>
</plist>
//
// Popover.swift
// Popover
//
// Created by corin8823 on 8/16/15.
// Copyright (c) 2015 corin8823. All rights reserved.
//
import Foundation
import UIKit
public enum PopoverOption {
case arrowSize(CGSize)
case animationIn(TimeInterval)
case animationOut(TimeInterval)
case cornerRadius(CGFloat)
case sideEdge(CGFloat)
case blackOverlayColor(UIColor)
case overlayBlur(UIBlurEffect.Style)
case type(PopoverType)
case color(UIColor)
case dismissOnBlackOverlayTap(Bool)
case showBlackOverlay(Bool)
case springDamping(CGFloat)
case initialSpringVelocity(CGFloat)
case sideOffset(CGFloat)
case borderColor(UIColor)
}
@objc public enum PopoverType: Int {
case up
case down
case left
case right
case auto
}
@objcMembers
open class Popover: UIView {
// custom property
open var arrowSize: CGSize = CGSize(width: 16.0, height: 10.0)
open var animationIn: TimeInterval = 0.6
open var animationOut: TimeInterval = 0.3
open var cornerRadius: CGFloat = 6.0
open var sideEdge: CGFloat = 20.0
open var popoverType: PopoverType = .down
open var blackOverlayColor: UIColor = UIColor(white: 0.0, alpha: 0.2)
open var overlayBlur: UIBlurEffect?
open var popoverColor: UIColor = UIColor.white
open var dismissOnBlackOverlayTap: Bool = true
open var showBlackOverlay: Bool = true
open var highlightFromView: Bool = false
open var highlightCornerRadius: CGFloat = 0
open var springDamping: CGFloat = 0.7
open var initialSpringVelocity: CGFloat = 3
open var sideOffset: CGFloat = 6.0
open var borderColor: UIColor?
// custom closure
open var willShowHandler: (() -> ())?
open var willDismissHandler: (() -> ())?
open var didShowHandler: (() -> ())?
open var didDismissHandler: (() -> ())?
public fileprivate(set) var blackOverlay: UIControl = UIControl()
fileprivate var containerView: UIView!
fileprivate var contentView: UIView!
fileprivate var contentViewFrame: CGRect!
fileprivate var arrowShowPoint: CGPoint!
public init() {
super.init(frame: .zero)
self.backgroundColor = .clear
self.accessibilityViewIsModal = true
}
public init(showHandler: (() -> ())?, dismissHandler: (() -> ())?) {
super.init(frame: .zero)
self.backgroundColor = .clear
self.didShowHandler = showHandler
self.didDismissHandler = dismissHandler
self.accessibilityViewIsModal = true
}
public init(options: [PopoverOption]?, showHandler: (() -> ())? = nil, dismissHandler: (() -> ())? = nil) {
super.init(frame: .zero)
self.backgroundColor = .clear
self.setOptions(options)
self.didShowHandler = showHandler
self.didDismissHandler = dismissHandler
self.accessibilityViewIsModal = true
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override open func layoutSubviews() {
super.layoutSubviews()
self.contentView.frame = self.bounds
}
open func showAsDialog(_ contentView: UIView) {
guard let rootView = UIApplication.shared.keyWindow else {
return
}
self.showAsDialog(contentView, inView: rootView)
}
open func showAsDialog(_ contentView: UIView, inView: UIView) {
self.arrowSize = .zero
let point = CGPoint(x: inView.center.x,
y: inView.center.y - contentView.frame.height / 2)
self.show(contentView, point: point, inView: inView)
}
open func show(_ contentView: UIView, fromView: UIView) {
guard let rootView = UIApplication.shared.keyWindow else {
return
}
self.show(contentView, fromView: fromView, inView: rootView)
}
open func show(_ contentView: UIView, fromView: UIView, inView: UIView) {
let point: CGPoint
//TODO: add left/right auto
if self.popoverType == .auto {
if let point = fromView.superview?.convert(fromView.frame.origin, to: nil),
point.y + fromView.frame.height + self.arrowSize.height + contentView.frame.height > inView.frame.height {
self.popoverType = .up
} else {
self.popoverType = .down
}
}
switch self.popoverType {
case .up:
point = inView.convert(
CGPoint(
x: fromView.frame.origin.x + (fromView.frame.size.width / 2),
y: fromView.frame.origin.y
), from: fromView.superview)
case .down, .auto:
point = inView.convert(
CGPoint(
x: fromView.frame.origin.x + (fromView.frame.size.width / 2),
y: fromView.frame.origin.y + fromView.frame.size.height
), from: fromView.superview)
case .left:
point = inView.convert(
CGPoint(x: fromView.frame.origin.x - sideOffset,
y: fromView.frame.origin.y + 0.5 * fromView.frame.height
), from: fromView.superview)
case .right:
point = inView.convert(
CGPoint(x: fromView.frame.origin.x + fromView.frame.size.width + sideOffset,
y: fromView.frame.origin.y + 0.5 * fromView.frame.height
), from: fromView.superview)
}
if self.highlightFromView {
self.createHighlightLayer(fromView: fromView, inView: inView)
}
self.show(contentView, point: point, inView: inView)
}
open func show(_ contentView: UIView, point: CGPoint) {
guard let rootView = UIApplication.shared.keyWindow else {
return
}
self.show(contentView, point: point, inView: rootView)
}
open func show(_ contentView: UIView, point: CGPoint, inView: UIView) {
if self.dismissOnBlackOverlayTap || self.showBlackOverlay {
self.blackOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.blackOverlay.frame = inView.bounds
inView.addSubview(self.blackOverlay)
if showBlackOverlay {
if let overlayBlur = self.overlayBlur {
let effectView = UIVisualEffectView(effect: overlayBlur)
effectView.frame = self.blackOverlay.bounds
effectView.isUserInteractionEnabled = false
self.blackOverlay.addSubview(effectView)
} else {
if !self.highlightFromView {
self.blackOverlay.backgroundColor = self.blackOverlayColor
}
self.blackOverlay.alpha = 0
}
}
if self.dismissOnBlackOverlayTap {
self.blackOverlay.addTarget(self, action: #selector(Popover.dismiss), for: .touchUpInside)
}
}
self.containerView = inView
self.contentView = contentView
self.contentView.backgroundColor = UIColor.clear
self.contentView.layer.cornerRadius = self.cornerRadius
self.contentView.layer.masksToBounds = true
self.arrowShowPoint = point
self.show()
}
open override func accessibilityPerformEscape() -> Bool {
self.dismiss()
return true
}
@objc open func dismiss() {
if self.superview != nil {
self.willDismissHandler?()
UIView.animate(withDuration: self.animationOut, delay: 0,
options: UIView.AnimationOptions(),
animations: {
self.transform = CGAffineTransform(scaleX: 0.0001, y: 0.0001)
self.blackOverlay.alpha = 0
}){ _ in
self.contentView.removeFromSuperview()
self.blackOverlay.removeFromSuperview()
self.removeFromSuperview()
self.transform = CGAffineTransform.identity
self.didDismissHandler?()
}
}
}
override open func draw(_ rect: CGRect) {
super.draw(rect)
let arrow = UIBezierPath()
let color = self.popoverColor
let arrowPoint = self.containerView.convert(self.arrowShowPoint, to: self)
switch self.popoverType {
case .up:
arrow.move(to: CGPoint(x: arrowPoint.x, y: self.bounds.height))
arrow.addLine(
to: CGPoint(
x: arrowPoint.x - self.arrowSize.width * 0.5,
y: self.isCornerLeftArrow ? self.arrowSize.height : self.bounds.height - self.arrowSize.height
)
)
arrow.addLine(to: CGPoint(x: self.cornerRadius, y: self.bounds.height - self.arrowSize.height))
arrow.addArc(
withCenter: CGPoint(
x: self.cornerRadius,
y: self.bounds.height - self.arrowSize.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(90),
endAngle: self.radians(180),
clockwise: true)
arrow.addLine(to: CGPoint(x: 0, y: self.cornerRadius))
arrow.addArc(
withCenter: CGPoint(
x: self.cornerRadius,
y: self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(180),
endAngle: self.radians(270),
clockwise: true)
arrow.addLine(to: CGPoint(x: self.bounds.width - self.cornerRadius, y: 0))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width - self.cornerRadius,
y: self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(270),
endAngle: self.radians(0),
clockwise: true)
arrow.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height - self.arrowSize.height - self.cornerRadius))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width - self.cornerRadius,
y: self.bounds.height - self.arrowSize.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(0),
endAngle: self.radians(90),
clockwise: true)
arrow.addLine(
to: CGPoint(
x: arrowPoint.x + self.arrowSize.width * 0.5,
y: self.isCornerRightArrow ? self.arrowSize.height : self.bounds.height - self.arrowSize.height
)
)
case .down, .auto:
arrow.move(to: CGPoint(x: arrowPoint.x, y: 0))
if self.isCloseToCornerRightArrow && !self.isCornerRightArrow {
if !isBehindCornerRightArrow {
arrow.addLine(to: CGPoint(x: self.bounds.width - self.cornerRadius, y: self.arrowSize.height))
arrow.addArc(
withCenter: CGPoint(x: self.bounds.width - self.cornerRadius, y: self.arrowSize.height + self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(270.0),
endAngle: self.radians(0),
clockwise: true)
} else {
arrow.addLine(to: CGPoint(x: self.bounds.width, y: self.arrowSize.height + self.cornerRadius))
arrow.addLine(to: CGPoint(x: self.bounds.width, y: self.arrowSize.height))
}
} else {
arrow.addLine(
to: CGPoint(
x: self.isBehindCornerLeftArrow ? self.frame.minX - self.arrowSize.width * 0.5 : arrowPoint.x + self.arrowSize.width * 0.5,
y: self.isCornerRightArrow ? self.arrowSize.height + self.bounds.height : self.arrowSize.height
)
)
arrow.addLine(to: CGPoint(x: self.bounds.width - self.cornerRadius, y: self.arrowSize.height))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width - self.cornerRadius,
y: self.arrowSize.height + self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(270.0),
endAngle: self.radians(0),
clockwise: true)
}
arrow.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height - self.cornerRadius))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width - self.cornerRadius,
y: self.bounds.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(0),
endAngle: self.radians(90),
clockwise: true)
arrow.addLine(to: CGPoint(x: 0, y: self.bounds.height))
arrow.addArc(
withCenter: CGPoint(
x: self.cornerRadius,
y: self.bounds.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(90),
endAngle: self.radians(180),
clockwise: true)
arrow.addLine(to: CGPoint(x: 0, y: self.arrowSize.height + self.cornerRadius))
if !isBehindCornerLeftArrow {
arrow.addArc(
withCenter: CGPoint(
x: self.cornerRadius,
y: self.arrowSize.height + self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(180),
endAngle: self.radians(270),
clockwise: true)
}
if isBehindCornerRightArrow {
arrow.addLine(to: CGPoint(
x: self.bounds.width - self.arrowSize.width * 0.5,
y: self.isCornerLeftArrow ? self.arrowSize.height + self.bounds.height : self.arrowSize.height))
} else if isCloseToCornerLeftArrow && !isCornerLeftArrow {
() // skipping this line in that case
} else {
arrow.addLine(to: CGPoint(x: arrowPoint.x - self.arrowSize.width * 0.5,
y: self.isCornerLeftArrow ? self.arrowSize.height + self.bounds.height : self.arrowSize.height))
}
case .left:
arrow.move(to: CGPoint(x: self.bounds.width, y: self.bounds.height * 0.5))
arrow.addLine(
to: CGPoint(
x: self.bounds.width - self.arrowSize.height,
y: self.bounds.height * 0.5 + self.arrowSize.width * 0.5
))
arrow.addLine(to: CGPoint(x:self.bounds.width - self.arrowSize.height, y: self.bounds.height - self.cornerRadius))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width - self.arrowSize.height - self.cornerRadius,
y: self.bounds.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(0.0),
endAngle: self.radians(90),
clockwise: true)
arrow.addLine(to: CGPoint(x: self.cornerRadius, y: self.bounds.height))
arrow.addArc(
withCenter: CGPoint(
x: self.cornerRadius,
y: self.bounds.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(90),
endAngle: self.radians(180),
clockwise: true)
arrow.addLine(to: CGPoint(x: 0, y: self.cornerRadius))
arrow.addArc(
withCenter: CGPoint(
x: self.cornerRadius,
y: self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(180),
endAngle: self.radians(270),
clockwise: true)
arrow.addLine(to: CGPoint(x: self.bounds.width - self.arrowSize.height - self.cornerRadius, y: 0))
arrow.addArc(
withCenter: CGPoint(x: self.bounds.width - self.arrowSize.height - self.cornerRadius,
y: self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(270),
endAngle: self.radians(0),
clockwise: true)
arrow.addLine(to: CGPoint(x: self.bounds.width - self.arrowSize.height,
y: self.bounds.height * 0.5 - self.arrowSize.width * 0.5
))
case .right:
arrow.move(to: CGPoint(x: arrowPoint.x, y: self.bounds.height * 0.5))
arrow.addLine(
to: CGPoint(
x: arrowPoint.x + self.arrowSize.height,
y: self.bounds.height * 0.5 + 0.5 * self.arrowSize.width
))
arrow.addLine(
to: CGPoint(
x: arrowPoint.x + self.arrowSize.height,
y: self.bounds.height - self.cornerRadius
))
arrow.addArc(
withCenter: CGPoint(
x: arrowPoint.x + self.arrowSize.height + self.cornerRadius,
y: self.bounds.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(180.0),
endAngle: self.radians(90),
clockwise: false)
arrow.addLine(to: CGPoint(x: self.bounds.width + arrowPoint.x - self.cornerRadius, y: self.bounds.height))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width + arrowPoint.x - self.cornerRadius,
y: self.bounds.height - self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(90),
endAngle: self.radians(0),
clockwise: false)
arrow.addLine(to: CGPoint(x: self.bounds.width + arrowPoint.x, y: self.cornerRadius))
arrow.addArc(
withCenter: CGPoint(
x: self.bounds.width + arrowPoint.x - self.cornerRadius,
y: self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(0),
endAngle: self.radians(-90),
clockwise: false)
arrow.addLine(to: CGPoint(x: arrowPoint.x + self.arrowSize.height - self.cornerRadius, y: 0))
arrow.addArc(
withCenter: CGPoint(x: arrowPoint.x + self.arrowSize.height + self.cornerRadius,
y: self.cornerRadius
),
radius: self.cornerRadius,
startAngle: self.radians(-90),
endAngle: self.radians(-180),
clockwise: false)
arrow.addLine(to: CGPoint(x: arrowPoint.x + self.arrowSize.height,
y: self.bounds.height * 0.5 - self.arrowSize.width * 0.5))
}
color.setFill()
arrow.fill()
if let borderColor = borderColor {
borderColor.setStroke()
arrow.stroke()
}
}
}
private extension Popover {
func setOptions(_ options: [PopoverOption]?){
if let options = options {
for option in options {
switch option {
case let .arrowSize(value):
self.arrowSize = value
case let .animationIn(value):
self.animationIn = value
case let .animationOut(value):
self.animationOut = value
case let .cornerRadius(value):
self.cornerRadius = value
case let .sideEdge(value):
self.sideEdge = value
case let .blackOverlayColor(value):
self.blackOverlayColor = value
case let .overlayBlur(style):
self.overlayBlur = UIBlurEffect(style: style)
case let .type(value):
self.popoverType = value
case let .color(value):
self.popoverColor = value
case let .dismissOnBlackOverlayTap(value):
self.dismissOnBlackOverlayTap = value
case let .showBlackOverlay(value):
self.showBlackOverlay = value
case let .springDamping(value):
self.springDamping = value
case let .initialSpringVelocity(value):
self.initialSpringVelocity = value
case let .sideOffset(value):
self.sideOffset = value
case let .borderColor(value):
self.borderColor = value
}
}
}
}
func create() {
var frame = self.contentView.frame
switch self.popoverType {
case .up, .down, .auto:
frame.origin.x = self.arrowShowPoint.x - frame.size.width * 0.5
case .left, .right:
frame.origin.y = self.arrowShowPoint.y - frame.size.height * 0.5
}
var sideEdge: CGFloat = 0.0
if frame.size.width < self.containerView.frame.size.width {
sideEdge = self.sideEdge
}
let outerSideEdge = frame.maxX - self.containerView.bounds.size.width
if outerSideEdge > 0 {
frame.origin.x -= (outerSideEdge + sideEdge)
} else {
if frame.minX < 0 {
frame.origin.x += abs(frame.minX) + sideEdge
}
}
self.frame = frame
let arrowPoint = self.containerView.convert(self.arrowShowPoint, to: self)
var anchorPoint: CGPoint
switch self.popoverType {
case .up:
frame.origin.y = self.arrowShowPoint.y - frame.height - self.arrowSize.height
anchorPoint = CGPoint(x: arrowPoint.x / frame.size.width, y: 1)
case .down, .auto:
frame.origin.y = self.arrowShowPoint.y
anchorPoint = CGPoint(x: arrowPoint.x / frame.size.width, y: 0)
case .left:
frame.origin.x = self.arrowShowPoint.x - frame.size.width - self.arrowSize.height
anchorPoint = CGPoint(x: 1, y: 0.5)
case .right:
frame.origin.x = self.arrowShowPoint.x
anchorPoint = CGPoint(x: 0, y: 0.5)
}
if self.arrowSize == .zero {
anchorPoint = CGPoint(x: 0.5, y: 0.5)
}
let lastAnchor = self.layer.anchorPoint
self.layer.anchorPoint = anchorPoint
let x = self.layer.position.x + (anchorPoint.x - lastAnchor.x) * self.layer.bounds.size.width
let y = self.layer.position.y + (anchorPoint.y - lastAnchor.y) * self.layer.bounds.size.height
self.layer.position = CGPoint(x: x, y: y)
switch self.popoverType {
case .up, .down, .auto:
frame.size.height += self.arrowSize.height
case .left, .right:
frame.size.width += self.arrowSize.height
}
self.frame = frame
}
func createHighlightLayer(fromView: UIView, inView: UIView) {
let path = UIBezierPath(rect: inView.bounds)
let highlightRect = inView.convert(fromView.frame, from: fromView.superview)
let highlightPath = UIBezierPath(roundedRect: highlightRect, cornerRadius: self.highlightCornerRadius)
path.append(highlightPath)
path.usesEvenOddFillRule = true
let fillLayer = CAShapeLayer()
fillLayer.path = path.cgPath
fillLayer.fillRule = CAShapeLayerFillRule.evenOdd
fillLayer.fillColor = self.blackOverlayColor.cgColor
self.blackOverlay.layer.addSublayer(fillLayer)
}
func show() {
self.setNeedsDisplay()
switch self.popoverType {
case .up:
self.contentView.frame.origin.y = 0.0
case .down, .auto:
self.contentView.frame.origin.y = self.arrowSize.height
case .left, .right:
self.contentView.frame.origin.x = 0
}
self.addSubview(self.contentView)
self.containerView.addSubview(self)
self.create()
self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
self.willShowHandler?()
UIView.animate(
withDuration: self.animationIn,
delay: 0,
usingSpringWithDamping: self.springDamping,
initialSpringVelocity: self.initialSpringVelocity,
options: UIView.AnimationOptions(),
animations: {
self.transform = CGAffineTransform.identity
}){ _ in
self.didShowHandler?()
}
UIView.animate(
withDuration: self.animationIn / 3,
delay: 0,
options: .curveLinear,
animations: {
self.blackOverlay.alpha = 1
}, completion: nil)
}
var isCloseToCornerLeftArrow: Bool {
return self.arrowShowPoint.x < self.frame.origin.x + arrowSize.width/2 + cornerRadius
}
var isCloseToCornerRightArrow: Bool {
return self.arrowShowPoint.x > (self.frame.origin.x + self.bounds.width) - arrowSize.width/2 - cornerRadius
}
var isCornerLeftArrow: Bool {
return self.arrowShowPoint.x == self.frame.origin.x
}
var isCornerRightArrow: Bool {
return self.arrowShowPoint.x == self.frame.origin.x + self.bounds.width
}
var isBehindCornerLeftArrow: Bool {
return self.arrowShowPoint.x < self.frame.origin.x
}
var isBehindCornerRightArrow: Bool {
return self.arrowShowPoint.x > self.frame.origin.x + self.bounds.width
}
func radians(_ degrees: CGFloat) -> CGFloat {
return CGFloat.pi * degrees / 180
}
}
Copyright (c) 2020 corin8823 <yusuke_takahashi@cyberagent.co.jp>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Popover
[![CI Status](http://img.shields.io/travis/corin8823/Popover.svg?style=flat)](https://travis-ci.org/corin8823/Popover)
[![Version](https://img.shields.io/cocoapods/v/Popover.svg?style=flat)](http://cocoapods.org/pods/Popover)
[![License](https://img.shields.io/cocoapods/l/Popover.svg?style=flat)](http://cocoapods.org/pods/Popover)
[![Platform](https://img.shields.io/cocoapods/p/Popover.svg?style=flat)](http://cocoapods.org/pods/Popover)
## Description and [appetize.io`s DEMO](https://appetize.io/app/q4n81yf0aakkx20x2cejh107b4)
![](https://github.com/corin8823/Popover/blob/master/ScreenShots/Screenshot.gif)
## Usage
To run the example project, clone the repo, and run `pod install` from the Example directory first.
### Simple
```swift
let startPoint = CGPoint(x: self.view.frame.width - 60, y: 55)
let aView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 180))
let popover = Popover()
popover.show(aView, point: startPoint)
```
### Custom
```swift
@IBOutlet weak var leftBottomButton: UIButton!
let width = self.view.frame.width / 4
let aView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: width))
let options = [
.type(.up),
.cornerRadius(width / 2),
.animationIn(0.3),
.blackOverlayColor(UIColor.red),
.arrowSize(CGSize.zero)
] as [PopoverOption]
let popover = Popover(options: options, showHandler: nil, dismissHandler: nil)
popover.show(aView, fromView: self.leftBottomButton)
```
## Requirements
- iOS 9.0+
- Swift 5
## Installation
### CocoaPods (iOS 8+)
Popover is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your `Podfile`:
```ruby
use_frameworks!
pod "Popover"
```
### Carthage (iOS 8+)
You can use [Carthage](https://github.com/Carthage/Carthage) to install `Popover` by adding it to your `Cartfile`:
```ruby
github "corin8823/Popover"
```
### Manual Installation
The class file required for Popover is located in the Classes folder in the root of this repository as listed below:
```
Popover.swift
```
## Customization
### Enum
- ``case arrowSize(CGSize)``
- ``case animationIn(NSTimeInterval)``
- ``case animationOut(NSTimeInterval)``
- ``case cornerRadius(CGFloat)``
- ``case sideEdge(CGFloat)``
- ``case blackOverlayColor(UIColor)``
- ``case overlayBlur(UIBlurEffectStyle)``
- ``case type(Popover.PopoverType)``
- ``case color(UIColor)``
- ``case dismissOnBlackOverlayTap(Bool)``
- ``case showBlackOverlay(Bool)``
### Property
- ``arrowSize: CGSize = CGSize(width: 16.0, height: 10.0)``
- ``animationIn: NSTimeInterval = 0.6``
- ``animationOut: NSTimeInterval = 0.3``
- ``cornerRadius: CGFloat = 6.0``
- ``sideEdge: CGFloat = 20.0``
- ``popoverType: PopoverType = .down``
- ``blackOverlayColor: UIColor = UIColor(white: 0.0, alpha: 0.2)``
- ``overlayBlur: UIBlurEffect?``
- ``popoverColor: UIColor = UIColor.white``
## Acknowledgments
Inspired by [DXPopover](https://github.com/xiekw2010/DXPopover) in [xiekw2010](https://github.com/xiekw2010)
## License
Popover is available under the MIT license. See the LICENSE file for more info.
# Acknowledgements
This application makes use of the following third party libraries:
## Popover
Copyright (c) 2020 corin8823 <yusuke_takahashi@cyberagent.co.jp>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## ZJTableViewManager
Copyright (c) 2018 Javen (https://github.com/JavenZ).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Generated by CocoaPods - https://cocoapods.org
......@@ -12,6 +12,63 @@
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2020 corin8823 &lt;yusuke_takahashi@cyberagent.co.jp&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>Popover</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2018 Javen (https://github.com/JavenZ).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>ZJTableViewManager</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
......
${PODS_ROOT}/Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-frameworks.sh
${BUILT_PRODUCTS_DIR}/Popover/Popover.framework
${BUILT_PRODUCTS_DIR}/ZJTableViewManager/ZJTableViewManager.framework
\ No newline at end of file
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Popover.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZJTableViewManager.framework
\ No newline at end of file
${PODS_ROOT}/Target Support Files/Pods-BreastFeedingDemo/Pods-BreastFeedingDemo-frameworks.sh
${BUILT_PRODUCTS_DIR}/Popover/Popover.framework
${BUILT_PRODUCTS_DIR}/ZJTableViewManager/ZJTableViewManager.framework
\ No newline at end of file
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Popover.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZJTableViewManager.framework
\ No newline at end of file
#!/bin/sh
set -e
set -u
set -o pipefail
function on_error {
echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
}
trap 'on_error $LINENO' ERR
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
# frameworks to, so exit 0 (signalling the script phase was successful).
exit 0
fi
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
BCSYMBOLMAP_DIR="BCSymbolMaps"
# This protects against multiple targets copying the same framework dependency at the same time. The solution
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
# Copies and strips a vendored framework
install_framework()
{
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
local source="${BUILT_PRODUCTS_DIR}/$1"
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
elif [ -r "$1" ]; then
local source="$1"
fi
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -L "${source}" ]; then
echo "Symlinked..."
source="$(readlink "${source}")"
fi
if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
# Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
echo "Installing $f"
install_bcsymbolmap "$f" "$destination"
rm "$f"
done
rmdir "${source}/${BCSYMBOLMAP_DIR}"
fi
# Use filter instead of exclude so missing patterns don't throw errors.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
local basename
basename="$(basename -s .framework "$1")"
binary="${destination}/${basename}.framework/${basename}"
if ! [ -r "$binary" ]; then
binary="${destination}/${basename}"
elif [ -L "${binary}" ]; then
echo "Destination binary is symlinked..."
dirname="$(dirname "${binary}")"
binary="${dirname}/$(readlink "${binary}")"
fi
# Strip invalid architectures so "fat" simulator / device frameworks work on device
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
strip_invalid_archs "$binary"
fi
# Resign the code if required by the build settings to avoid unstable apps
code_sign_if_enabled "${destination}/$(basename "$1")"
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
local swift_runtime_libs
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
for lib in $swift_runtime_libs; do
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
code_sign_if_enabled "${destination}/${lib}"
done
fi
}
# Copies and strips a vendored dSYM
install_dsym() {
local source="$1"
warn_missing_arch=${2:-true}
if [ -r "$source" ]; then
# Copy the dSYM into the targets temp dir.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
local basename
basename="$(basename -s .dSYM "$source")"
binary_name="$(ls "$source/Contents/Resources/DWARF")"
binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
# Strip invalid architectures from the dSYM.
if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
strip_invalid_archs "$binary" "$warn_missing_arch"
fi
if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
# Move the stripped file into its final destination.
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
else
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
fi
fi
}
# Used as a return value for each invocation of `strip_invalid_archs` function.
STRIP_BINARY_RETVAL=0
# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
warn_missing_arch=${2:-true}
# Get architectures for current target binary
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
# Intersect them with the architectures we are building for
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
# If there are no archs supported by this binary then warn the user
if [[ -z "$intersected_archs" ]]; then
if [[ "$warn_missing_arch" == "true" ]]; then
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
fi
STRIP_BINARY_RETVAL=1
return
fi
stripped=""
for arch in $binary_archs; do
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary"
stripped="$stripped $arch"
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
STRIP_BINARY_RETVAL=0
}
# Copies the bcsymbolmap files of a vendored framework
install_bcsymbolmap() {
local bcsymbolmap_path="$1"
local destination="${BUILT_PRODUCTS_DIR}"
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
}
# Signs a framework with the provided identity
code_sign_if_enabled() {
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
# Use the current code_sign_identity
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
code_sign_cmd="$code_sign_cmd &"
fi
echo "$code_sign_cmd"
eval "$code_sign_cmd"
fi
}
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/Popover/Popover.framework"
install_framework "${BUILT_PRODUCTS_DIR}/ZJTableViewManager/ZJTableViewManager.framework"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/Popover/Popover.framework"
install_framework "${BUILT_PRODUCTS_DIR}/ZJTableViewManager/ZJTableViewManager.framework"
fi
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
wait
fi
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Popover" "${PODS_CONFIGURATION_BUILD_DIR}/ZJTableViewManager"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Popover/Popover.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZJTableViewManager/ZJTableViewManager.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
OTHER_LDFLAGS = $(inherited) -framework "Popover" -framework "ZJTableViewManager"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Popover" "${PODS_CONFIGURATION_BUILD_DIR}/ZJTableViewManager"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Popover/Popover.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ZJTableViewManager/ZJTableViewManager.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
OTHER_LDFLAGS = $(inherited) -framework "Popover" -framework "ZJTableViewManager"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.3.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_Popover : NSObject
@end
@implementation PodsDummy_Popover
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double PopoverVersionNumber;
FOUNDATION_EXPORT const unsigned char PopoverVersionString[];
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Popover
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Popover
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module Popover {
umbrella header "Popover-umbrella.h"
export *
module * { export * }
}
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Popover
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Popover
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_ZJTableViewManager : NSObject
@end
@implementation PodsDummy_ZJTableViewManager
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double ZJTableViewManagerVersionNumber;
FOUNDATION_EXPORT const unsigned char ZJTableViewManagerVersionString[];
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ZJTableViewManager
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/ZJTableViewManager
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module ZJTableViewManager {
umbrella header "ZJTableViewManager-umbrella.h"
export *
module * { export * }
}
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ZJTableViewManager
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/ZJTableViewManager
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
Copyright (c) 2018 Javen (https://github.com/JavenZ).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\ No newline at end of file
[English introduction](https://github.com/JavenZ/ZJTableViewManager/blob/master/README_EN.md)
### 关于ZJTableViewManager
强大的数据驱动的TableView,构建复杂TableView从未如此轻松。
### 使用
直接拖入ZJTableViewManager文件夹里面的文件,或者用cocoapods
`pod 'ZJTableViewManager', '~> 1.0.7'`
### 适配
| Version | Swift | Xcode |
| -------------- | --------- | ------------------ |
| 0.2.7 | 4.0 / 4.2 | Xcode10 or later |
| 1.0.3 or later | 4.0 ~ 5.2 | Xcode10.2 or later |
### 简介
[ZJTableViewManager](https://github.com/JavenZ/ZJTableViewManager) 基于数据驱动页面的理念,接管了`UITableView``delegate``dataSource`的逻辑,开发者只需要关心数据的处理,避免了冗长的判断,让代码更加易于维护。
比如一个页面里面是UITableView,有5种不同的Cell。按照传统的写法,`tableView(_:cellForRowAt:)`代理方法里会是这样:
```swift
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if condition1 {
return SimpleStringCell
}else if condition2 {
return FullLengthTextFieldCell
}else if condition3 {
return TextCell
}else if condition4 {
return PasswordCell
}else if condition5 {
return SwitchCell
}else {
return DefaultCell
}
}
```
同时下面两个方法里面也很可能需要写上这一串判断条件。显而易见的缺点:代码冗长
```swift
tableView(_:, heightForRowAt:)
tableView(_:, didSelectRowAt:)
```
其次,实际项目中,很多人直接用`IndexPath`作为判断条件,大量`if else`,且当需要对`Cell`显示顺序做调整时,基于`IndexPath`的判断就会出问题,改起来特别容易出现Bug。
当然有经验的程序员会抽象出一个`type`,通过`type`来判断`Cell`类型,避免`IndexPath`的缺陷。这其实已经算是一种数据驱动的思想了,相比用`IndexPath`判断,更加不容易出问题。但是这还不够,这些方法里面依然会有很多`if else`,影响观感也影响逻辑理解。
**所以[ZJTableViewManager](https://github.com/JavenZ/ZJTableViewManager) 在以上的基础上进一步做了封装,效果如下:**
![](https://upload-images.jianshu.io/upload_images/1653855-235590ab7042ec24.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**就如示例代码所示,不需要处理TableView的delegate和dataSource,不需要那些`if else`,Item控制Cell处理Cell的事件,我们只要专心用代码描述这个TableView长什么样子,它就会按照我们描述的样子搭建出来。**
### 使用方式
#### 1.系统默认Cell
创建系统默认的cell,使用ZJTableViewItem类,创建之后加入section即可
```swift
let item = ZJTableViewItem(title: "测试cell 1")
section.add(item: item)
```
根据需要可以修改样式为`subtitle`
```swift
item.style = .subtitle
item.detailLabelText = "detail label text"
```
运行结果:
![](https://upload-images.jianshu.io/upload_images/1653855-d5dd7f7890aae7e4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**总结一下系统默认Cell的使用步骤:**
1. 页面上创建一个TableView(StoryBoard拖或者纯代码创建都可以)
2. 通过这个TableView初始化一个manager
3. 创建一个Section,加入到manager里
4. 创建Cell对应的Item,赋值之后加入到section里
5. `manager.reload()`
具体不展开说了,系统cell就那几个样式,平时也很少用到,自己尝试吧。
#### 2.自定义Cell
自定义Cell才是我们实际项目中用到最多的,所以这一块需要详细说一下。
我们来尝试自定义这样一个Cell
![](https://upload-images.jianshu.io/upload_images/1653855-127f15ffb418928d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
左边是一个UILabel,右边一个UISwitch,功能是在UISwitch开关时会发出回调,在VC中处理。
首先,新建一个ZJSwitchCell类,继承自UITableViewCell,勾选上Also create XIB file(当然不用XIB,纯代码布局也可以)
![](https://upload-images.jianshu.io/upload_images/1653855-b483247676b353fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
在xib文件里面拖上控件,并且把控件和UISwitch的value change事件拖线到Cell文件里面:
![](https://upload-images.jianshu.io/upload_images/1653855-dd3722b4e90e93a4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://upload-images.jianshu.io/upload_images/1653855-0319d60626b755c5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**下面是重点:**
在ZJSwitchCell.swift文件里面写一个ZJSwitchCellItem类,继承自ZJTableViewItem,有三个属性,标题title,开关状态isOn,回调闭包didChanged。
![](https://upload-images.jianshu.io/upload_images/1653855-987d09829c0c8c46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
让ZJSwitchCell遵循ZJCellProtocol协议,如图所示,Xcode会弹出提示,点击fix,会自动加上需要的方法和类型
![](https://upload-images.jianshu.io/upload_images/1653855-7a180aa4b0738837.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
ZJCelltemClass这里填写上前面写好的ZJSwitchCellItem类名
![](https://upload-images.jianshu.io/upload_images/1653855-77c0c7dddde5d25b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
然后Xcode还会有个错误提示,继续点fix,就好了。
![](https://upload-images.jianshu.io/upload_images/1653855-d8cbf7d997086d67.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**可能有时候Xcode自动fix补全的代码有问题,比如说`typealias ZJCelltemClass = `出现两遍或者根本没有fix按钮,不要慌,cmd+b编译一下,再试试就好了**
**然后在`cellWillAppear()`方法里面写上赋值操作,它等价于`tableView(_:, cellForRowAt:)`方法。再到`valueChanged(:)`方法里面,记录UISwitch的状态,并把当前这个item通过回调传出去。Cell部分的自定义就完成了。**
![](https://upload-images.jianshu.io/upload_images/1653855-0cb0f5ae02200802.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
最后,在VC里面使用,使用之前需要`manager.register(ZJSwitchCell.self, ZJSwitchItem.self)`注册一下,这和之前使用系统默认的Cell有区别,自定义的Cell都需要注册一下才可以使用。
```swift
class FormViewController: UIViewController {
var tableView: UITableView!
var manager: ZJTableViewManager!
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds, style: .plain)
view.addSubview(tableView)
manager = ZJTableViewManager(tableView: tableView)
manager.register(ZJSwitchCell.self, ZJSwitchItem.self)
let section = ZJTableViewSection()
manager.add(section: section)
// Switch Item
section.add(item: ZJSwitchItem(title: "Switch Item", isOn: false, didChanged: { item in
zj_log(item.isOn)
}))
manager.reload()
}
}
```
**总结一下自定义Cell的步骤:**
1. 新建Cell(XIB或者纯代码都可以)
2. 创建Cell对应的Item,通过Item给Cell传值(**实际项目中一般是用Item持有Model,在`cellWillAppear()`中通过item.model取值并赋值到控件里面**
3. 在VC中给把Cell向TableViewManager注册。
其余使用方式参考上面系统默认Cell的使用。
#### 3.Cell固定高度及动态计算高度处理
前面示例的两种Cell高度都是系统默认的44,我们实际项目中需要不同高度的Cell,怎么处理呢?
**固定高度:**
聪明的同学可能已经发现了,Item控制了Cell的所有表现,所以肯定是通过Item来控制的。Item中有个cellHeight属性,只要给它赋值,就能够控制Cell的高度。
我们可以重写Item对象的init()方法,在里面给一个固定的高度
```swift
override init() {
super.init()
cellHeight = 100
}
```
或者在VC里面初始化Item之后,再给cellHeight赋值,都是可以的。
**动态高度:**
动态高度的前提是使用AutoLayout布局,约束没有缺失,然后在Item赋值好了之后,调用一下autoHeight(:)方法,高度就算好了。
```swift
let item = AutomaticHeightCellItem()
item.feed = feed
//计算高度
item.autoHeight(manager)
//把cell加入进section
section.add(item: item)
```
具体可以看下面的文章,里面说的更详细,这里不展开说了。
[Swift UITableViewCell高性能动态计算高度](https://www.jianshu.com/p/34c495942ed4)
#### 4.TableView相关事件(如点击事件)
设置点击事件回调:
```swift
item.setSelectionHandler { (callBackItem: LevelCellItem) in
//Do some thing
}
```
其他事件同理,包括section的一些事件(比如section即将出现之类的回调),具体看Demo。
#### 5.Scroll事件的代理
我们在使用TableView的同时,有时还需要处理Scroll事件,比如说判断滚动已经停止,或者监听滚动事件等,可以通过设置`manager.scrollDelegate = self`并遵循`ZJTableViewScrollDelegate `的方式,获取所有滚动事件的回调,使用方式和`UIScrollViewDelegate`一样。
### Demo:
电商项目的评价、打星评分、添加评论图片,
![image](https://github.com/JavenZ/ZJTableViewManager/blob/master/ScreenShot/pictureitem_edit.gif?raw=true) ![image](https://github.com/JavenZ/ZJTableViewManager/blob/master/ScreenShot/pictrue_item_read.gif?raw=true)
这里主要有3个cell,一个打星的cell,一个评论的cell,一个添加图片的cell。viewController里只有20行代码,耦合性低。
```swift
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Demo"
self.manager = ZJTableViewManager(tableView: self.tableView)
//register cell
self.manager?.register(OrderEvaluateCell.self, OrderEvaluateItem.self)
self.manager?.register(ZJPictureTableCell.self, ZJPictureTableItem.self)
//add section
let section = ZJTableViewSection(headerHeight: 10, color: UIColor.init(white: 0.9, alpha: 1))
self.manager?.add(section: section)
//add cells
for i in 0...10 {
i //评价cell
section.add(item: OrderEvaluateItem(title: "评价"))
let textItem = ZJTextItem(text: nil, placeHolder: "请在此输入您的评价~", ddChanged: nil)
textItem.isHideSeparator = true
section.add(item: textItem)
//图片cell
if i%2 == 1 {
//只展示图片
let pictureItem = ZJPictureTableItem(maxNumber: 5, column: 4, space: 15, width: self.view.frame.size.width, superVC: self, pictures: [image])
pictureItem.type = .read
section.add(item: pictureItem)
}else{
//添加图片
let pictureItem = ZJPictureTableItem(maxNumber: 5, column: 4, space: 15, width: self.view.frame.size.width, superVC: self)
pictureItem.type = .edit
section.add(item: pictureItem)
}
}
}
```
### 注:
TableView可以storyboard、xib、纯代码初始化,cell可以xib或者纯代码构建
//
// ZJDefaultCell.swift
// NewRetail
//
// Created by Javen on 2018/2/8.
// Copyright © 2018年 . All rights reserved.
//
import UIKit
class ZJDefaultCell: UITableViewCell, ZJCellProtocol {
var item: ZJTableViewItem!
typealias ZJCellItemClass = ZJTableViewItem
func cellWillAppear() {}
}
//
// ZJProtocol.swift
// test
//
// Created by Jie Zhang on 2019/10/18.
// Copyright © 2019 Green Dot. All rights reserved.
//
import Foundation
import UIKit
// MARK: - ZJTableViewCellProtocol
public protocol ZJItemProtocol where Self: ZJTableViewItem {}
public protocol ZJInternalCellProtocol where Self: UITableViewCell {
var _item: ZJItemProtocol? { get set }
func cellWillAppear()
func cellDidAppear()
func cellDidDisappear()
}
public extension ZJInternalCellProtocol {
func cellDidAppear() {}
func cellDidDisappear() {}
}
public protocol ZJCellProtocol: ZJInternalCellProtocol {
associatedtype ZJCellItemClass: ZJItemProtocol
var item: ZJCellItemClass! { get set }
}
public extension ZJCellProtocol {
var _item: ZJItemProtocol? {
get {
return item
}
set {
item = (newValue as! Self.ZJCellItemClass)
}
}
}
extension ZJTableViewItem: ZJItemProtocol {}
// MARK: - ZJTableViewScrollDelegate
public protocol ZJTableViewScrollDelegate: NSObjectProtocol {
@available(iOS 2.0, *)
func scrollViewDidScroll(_ scrollView: UIScrollView) // any offset changes
@available(iOS 3.2, *)
func scrollViewDidZoom(_ scrollView: UIScrollView) // any zoom scale changes
// called on start of dragging (may require some time and or distance to move)
@available(iOS 2.0, *)
func scrollViewWillBeginDragging(_ scrollView: UIScrollView)
// called on finger up if the user dragged. velocity is in points/millisecond. targetContentOffset may be changed to adjust where the scroll view comes to rest
@available(iOS 5.0, *)
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
@available(iOS 2.0, *)
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
@available(iOS 2.0, *)
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) // called on finger up as we are moving
@available(iOS 2.0, *)
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) // called when scroll view grinds to a halt
@available(iOS 2.0, *)
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) // called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animating
@available(iOS 2.0, *)
func viewForZooming(in scrollView: UIScrollView) -> UIView? // return a view that will be scaled. if delegate returns nil, nothing happens
@available(iOS 3.2, *)
func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) // called before the scroll view begins zooming its content
@available(iOS 2.0, *)
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) // scale between minimum and maximum. called after any 'bounce' animations
@available(iOS 2.0, *)
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool // return a yes if you want to scroll to the top. if not defined, assumes YES
@available(iOS 2.0, *)
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) // called when scrolling animation finished. may be called immediately if already at top
/* Also see -[UIScrollView adjustedContentInsetDidChange]
*/
@available(iOS 11.0, *)
func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView)
}
// MARK: - ZJTableViewScrollDelegate Default Implementation
public extension ZJTableViewScrollDelegate {
func scrollViewDidScroll(_: UIScrollView) {}
func scrollViewDidZoom(_: UIScrollView) {}
func scrollViewWillBeginDragging(_: UIScrollView) {}
func scrollViewWillEndDragging(_: UIScrollView, withVelocity _: CGPoint, targetContentOffset _: UnsafeMutablePointer<CGPoint>) {}
func scrollViewDidEndDragging(_: UIScrollView, willDecelerate _: Bool) {}
func scrollViewWillBeginDecelerating(_: UIScrollView) {}
func scrollViewDidEndDecelerating(_: UIScrollView) {}
func scrollViewDidEndScrollingAnimation(_: UIScrollView) {}
func viewForZooming(in _: UIScrollView) -> UIView? { return nil }
func scrollViewWillBeginZooming(_: UIScrollView, with _: UIView?) {}
func scrollViewDidEndZooming(_: UIScrollView, with _: UIView?, atScale _: CGFloat) {}
func scrollViewShouldScrollToTop(_: UIScrollView) -> Bool { return true }
func scrollViewDidScrollToTop(_: UIScrollView) {}
func scrollViewDidChangeAdjustedContentInset(_: UIScrollView) {}
}
// MARK: - UIScrollViewDelegate
extension ZJTableViewManager: UIScrollViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewDidScroll(scrollView)
}
}
public func scrollViewDidZoom(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewDidZoom(scrollView)
}
}
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewWillBeginDragging(scrollView)
}
}
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if let d = scrollDelegate {
d.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
}
}
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if let d = scrollDelegate {
d.scrollViewDidEndDragging(scrollView, willDecelerate: decelerate)
}
}
public func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewWillBeginDecelerating(scrollView)
}
}
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewDidEndDecelerating(scrollView)
}
}
public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewDidEndScrollingAnimation(scrollView)
}
}
public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
if let d = scrollDelegate {
return d.viewForZooming(in: scrollView)
}
return nil
}
public func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
if let d = scrollDelegate {
d.scrollViewWillBeginZooming(scrollView, with: view)
}
}
public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
if let d = scrollDelegate {
d.scrollViewDidEndZooming(scrollView, with: view, atScale: scale)
}
}
public func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
if let d = scrollDelegate {
return d.scrollViewShouldScrollToTop(scrollView)
}
return true
}
public func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
d.scrollViewDidScrollToTop(scrollView)
}
}
public func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView) {
if let d = scrollDelegate {
if #available(iOS 11.0, *) {
d.scrollViewDidChangeAdjustedContentInset(scrollView)
} else {
// Fallback on earlier versions
}
}
}
}
//
// ZJTableViewItem.swift
// NewRetail
//
// Created by Javen on 2018/2/8.
// Copyright © 2018年 . All rights reserved.
//
import UIKit
public typealias ZJTableViewItemBlock = (ZJTableViewItem) -> Void
open class ZJTableViewItem: NSObject {
public var tableVManager: ZJTableViewManager {
return section.tableViewManager
}
private weak var _section: ZJTableViewSection?
public var section: ZJTableViewSection {
set {
_section = newValue
}
get {
guard let s = _section else { fatalError() }
return s
}
}
public var cellIdentifier: String!
/// cell高度(如果要自动计算高度,使用autoHeight(manager:)方法,框架会算出高度,具体看demo)
/// 传UITableViewAutomaticDimension则是系统实时计算高度,可能会有卡顿、reload弹跳等问题,不建议使用,有特殊需要可以选择使用
public var cellHeight: CGFloat!
/// cell点击事件的回调
public var selectionHandler: ZJTableViewItemBlock?
public func setSelectionHandler<T: ZJTableViewItem>(_ handler: ((_ callBackItem: T) -> Void)?) {
selectionHandler = { item in
handler?(item as! T)
}
}
public var deletionHandler: ZJTableViewItemBlock?
public func setDeletionHandler<T: ZJTableViewItem>(_ handler: ((_ callBackItem: T) -> Void)?) {
deletionHandler = { item in
handler?(item as! T)
}
}
public var labelText: String?
public var detailLabelText: String?
public var textAlignment: NSTextAlignment = .left
public var detailTextAlignment: NSTextAlignment = .left
public var image: UIImage?
public var highlightedImage: UIImage?
public var style: UITableViewCell.CellStyle = .default
public var accessoryType: UITableViewCell.AccessoryType = .none
public var selectionStyle: UITableViewCell.SelectionStyle = .default
public var editingStyle: UITableViewCell.EditingStyle = .none
public var accessoryView: UIView?
public var isSelected: Bool {
return cell.isSelected
}
public var isAllowSelect: Bool = true
public var indexPath: IndexPath {
let rowIndex = self.section.items.zj_indexOf(self)
let section = tableVManager.sections.zj_indexOf(self.section)
return IndexPath(item: rowIndex, section: section)
}
/// 尽量避免通过此属性直接修改cell里面的元素,直接修改cell没有修改修改数据源,由于TableViewCell的复用,会造成异常(正确做法是修改item的属性,通过item.reload()来刷新cell)
public var cell: UITableViewCell {
if let unwrappedCell = tableVManager.tableView.cellForRow(at: indexPath) {
return unwrappedCell
}
zj_log("没有获取到对应的cell,必须在tableView reload之后才能通过这个属性获取到cell。或者获取的indexPath对应的cell必须在屏幕内,无法获取屏幕外的cell")
fatalError()
}
override public init() {
super.init()
cellIdentifier = "\(type(of: self))"
cellHeight = 44
}
public convenience init(text: String?) {
self.init()
labelText = text
}
public func reload(_ animation: UITableView.RowAnimation) {
zj_log("reload tableview at \(indexPath)")
tableVManager.tableView.beginUpdates()
tableVManager.tableView.reloadRows(at: [indexPath], with: animation)
tableVManager.tableView.endUpdates()
}
public func select(animated: Bool = true, scrollPosition: UITableView.ScrollPosition = .none) {
if isAllowSelect {
tableVManager.tableView.selectRow(at: indexPath, animated: animated, scrollPosition: scrollPosition)
}
}
public func deselect(animated: Bool = true) {
tableVManager.tableView.deselectRow(at: indexPath, animated: animated)
}
public func delete(_ animation: UITableView.RowAnimation = .automatic) {
if section == nil {
zj_log("Item did not in section,please check section.add() method")
return
}
if !section.items.contains(where: { $0 == self }) {
zj_log("can't delete because this item did not in section")
return
}
let indexPath = self.indexPath
section.items.remove(at: indexPath.row)
tableVManager.tableView.deleteRows(at: [indexPath], with: animation)
}
/// 计算cell高度
///
/// - Parameters:
/// - manager: 当前tableview的manager
public func autoHeight(_ manager: ZJTableViewManager) {
guard let cell = manager.tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? ZJInternalCellProtocol else {
zj_log("please register cell")
return
}
cell._item = self
cell.cellWillAppear()
cellHeight = cell.systemLayoutSizeFitting(CGSize(width: manager.tableView.frame.width, height: 0), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel).height
}
}
//
// ZJTableViewManager.swift
// NewRetail
//
// Created by Javen on 2018/2/8.
// Copyright © 2018年 . All rights reserved.
//
import UIKit
public func zj_log(_ item: Any, file: String = #file, line: Int = #line) {
if ZJTableViewManager.isDebug {
var logEntry: String = String()
if let fileName = file.components(separatedBy: "/").last {
logEntry.append("[\(fileName):\(line)] ")
}
print(logEntry + "\(item)")
}
}
open class ZJTableViewManager: NSObject {
public static var isDebug = false
public weak var scrollDelegate: ZJTableViewScrollDelegate?
public var tableView: UITableView!
public var sections: [ZJTableViewSection] = []
var defaultTableViewSectionHeight: CGFloat {
return tableView.style == .grouped ? 44 : 0
}
public func selectedItem<T: ZJTableViewItem>() -> T? {
if let item = selectedItems().first {
return item as? T
}
return nil
}
public func selectedItems<T: ZJTableViewItem>() -> [T] {
if let indexPaths = tableView.indexPathsForSelectedRows {
var items = [T]()
for idx in indexPaths {
if let item = sections[idx.section].items[idx.row] as? T {
items.append(item)
}
}
return items
}
return []
}
public func selectItems(_ items: [ZJTableViewItem], animated: Bool = true, scrollPosition: UITableView.ScrollPosition = .none) {
for item in items {
item.select(animated: animated, scrollPosition: scrollPosition)
}
}
public func deselectItems(_ items: [ZJTableViewItem], animated: Bool = true) {
for item in items {
item.deselect(animated: animated)
}
}
public init(tableView: UITableView) {
super.init()
self.tableView = tableView
tableView.delegate = self
tableView.dataSource = self
tableView.layoutMargins = UIEdgeInsets.zero
tableView.estimatedRowHeight = 0
tableView.estimatedSectionFooterHeight = 0
tableView.estimatedSectionHeaderHeight = 0
}
/// use this method to update cell height after you change item.cellHeight.
public func updateHeight() {
tableView.beginUpdates()
tableView.endUpdates()
}
public func register(_ cell: ZJInternalCellProtocol.Type, _ item: ZJTableViewItem.Type, _ bundle: Bundle = Bundle.main) {
zj_log("\(cell) registered")
if bundle.path(forResource: "\(cell)", ofType: "nib") != nil {
tableView.register(UINib(nibName: "\(cell)", bundle: bundle), forCellReuseIdentifier: "\(item)")
} else {
tableView.register(cell, forCellReuseIdentifier: "\(item)")
}
}
func sectionFrom(section: Int) -> ZJTableViewSection {
let section = sections.count > section ? sections[section] : nil
assert(section != nil, "section out of range")
return section!
}
func getSectionAndItem(indexPath: (section: Int, row: Int)) -> (section: ZJTableViewSection, item: ZJTableViewItem) {
let section = sectionFrom(section: indexPath.section)
let item = section.items.count > indexPath.row ? section.items[indexPath.row] : nil
assert(item != nil, "row out of range")
return (section, item!)
}
public func add(section: ZJTableViewSection) {
if !section.isKind(of: ZJTableViewSection.self) {
zj_log("error section class")
return
}
section.tableViewManager = self
sections.append(section)
}
public func remove(section: Any) {
if !(section as AnyObject).isKind(of: ZJTableViewSection.self) {
zj_log("error section class")
return
}
sections.remove(at: sections.zj_indexOf(section as! ZJTableViewSection))
}
public func removeAllSections() {
sections.removeAll()
}
public func reload() {
tableView.reloadData()
}
}
// MARK: - UITableViewDelegate
extension ZJTableViewManager: UITableViewDelegate {
public func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
let obj = getSectionAndItem(indexPath: (section: indexPath.section, row: indexPath.row))
if obj.item.isAllowSelect {
return indexPath
} else {
return nil
}
}
public func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
let obj = getSectionAndItem(indexPath: (indexPath.section, indexPath.row))
obj.item.selectionHandler?(obj.item)
}
public func tableView(_: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
let obj = getSectionAndItem(indexPath: (section: indexPath.section, row: indexPath.row))
return obj.item.editingStyle
}
public func tableView(_: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let obj = getSectionAndItem(indexPath: (section: indexPath.section, row: indexPath.row))
if editingStyle == .delete {
if let handler = obj.item.deletionHandler {
handler(obj.item)
}
}
}
public func tableView(_: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt _: IndexPath) {
(cell as! ZJInternalCellProtocol).cellDidDisappear()
}
public func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt _: IndexPath) {
(cell as! ZJInternalCellProtocol).cellDidAppear()
}
public func tableView(_: UITableView, willDisplayHeaderView _: UIView, forSection section: Int) {
let sectionModel = sectionFrom(section: section)
sectionModel.headerWillDisplayHandler?(sectionModel)
}
public func tableView(_: UITableView, didEndDisplayingHeaderView _: UIView, forSection section: Int) {
// 这里要做一个保护,因为这个方法在某个section被删除之后reload tableView, 会最后触发一次这个
// section的endDisplaying方法,这时去根据section去获取section对象会获取不到。
if sections.count > section {
let sectionModel = sectionFrom(section: section)
sectionModel.headerDidEndDisplayHandler?(sectionModel)
}
}
public func tableView(_: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionModel = sectionFrom(section: section)
return sectionModel.headerView
}
public func tableView(_: UITableView, viewForFooterInSection section: Int) -> UIView? {
let sectionModel = sectionFrom(section: section)
return sectionModel.footerView
}
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
let sectionModel = sectionFrom(section: section)
if sectionModel.headerView != nil || (sectionModel.headerHeight > 0 && sectionModel.headerHeight != CGFloat.leastNormalMagnitude) {
return sectionModel.headerHeight
}
if let title = sectionModel.headerTitle {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.frame.width - 40, height: CGFloat.greatestFiniteMagnitude))
label.text = title
label.font = UIFont.preferredFont(forTextStyle: .footnote)
label.sizeToFit()
return label.frame.height + 20.0
} else {
return defaultTableViewSectionHeight
}
}
public func tableView(_: UITableView, heightForFooterInSection section: Int) -> CGFloat {
let sectionModel = sectionFrom(section: section)
return sectionModel.footerHeight
}
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let section = sections[indexPath.section]
let item = section.items[indexPath.row]
#if swift(>=4.2)
if item.cellHeight == UITableView.automaticDimension, tableView.estimatedRowHeight == 0 {
tableView.estimatedRowHeight = 44
tableView.estimatedSectionFooterHeight = 44
tableView.estimatedSectionHeaderHeight = 44
}
#else
if item.cellHeight == UITableViewAutomaticDimension, tableView.estimatedRowHeight == 0 {
tableView.estimatedRowHeight = 44
tableView.estimatedSectionFooterHeight = 44
tableView.estimatedSectionHeaderHeight = 44
}
#endif
return item.cellHeight
}
}
// MARK: - UITableViewDataSource
extension ZJTableViewManager: UITableViewDataSource {
public func numberOfSections(in _: UITableView) -> Int {
return sections.count
}
public func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
let sectionModel = sectionFrom(section: section)
return sectionModel.headerTitle
}
public func tableView(_: UITableView, titleForFooterInSection section: Int) -> String? {
let sectionModel = sectionFrom(section: section)
return sectionModel.footerTitle
}
public func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionModel = sectionFrom(section: section)
return sectionModel.items.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let (_, item) = getSectionAndItem(indexPath: (indexPath.section, indexPath.row))
var cell = tableView.dequeueReusableCell(withIdentifier: item.cellIdentifier) as? ZJInternalCellProtocol
if cell == nil {
cell = (ZJDefaultCell(style: item.style, reuseIdentifier: item.cellIdentifier) as ZJInternalCellProtocol)
}
let unwrappedCell = cell!
unwrappedCell.textLabel?.text = item.labelText
unwrappedCell.textLabel?.textAlignment = item.textAlignment
unwrappedCell.detailTextLabel?.text = item.detailLabelText
unwrappedCell.detailTextLabel?.textAlignment = item.detailTextAlignment
unwrappedCell.accessoryView = item.accessoryView
unwrappedCell.imageView?.image = item.image
unwrappedCell.imageView?.highlightedImage = item.highlightedImage
unwrappedCell.accessoryType = item.accessoryType
unwrappedCell.selectionStyle = item.selectionStyle
unwrappedCell._item = item
unwrappedCell.cellWillAppear()
return unwrappedCell
}
}
extension Array where Element: Equatable {
func zj_indexOf(_ element: Element) -> Int {
var index: Int?
#if swift(>=5)
index = firstIndex { (e) -> Bool in
e == element
}
#else
index = self.index(where: { (e) -> Bool in
e == element
})
#endif
assert(index != nil, "Can't find element in array, please check you code")
return index!
}
}
//
// ZJTableViewSection.swift
// NewRetail
//
// Created by Javen on 2018/2/8.
// Copyright © 2018年 . All rights reserved.
//
import UIKit
public typealias ZJTableViewSectionBlock = (ZJTableViewSection) -> Void
open class ZJTableViewSection: NSObject {
private weak var _tableViewManager: ZJTableViewManager?
public var tableViewManager: ZJTableViewManager {
set {
_tableViewManager = newValue
}
get {
guard let tableViewManager = _tableViewManager else {
zj_log("Please add section to manager")
fatalError()
}
return tableViewManager
}
}
public var items = [ZJTableViewItem]()
public var headerHeight: CGFloat!
public var footerHeight: CGFloat!
public var headerView: UIView?
public var footerView: UIView?
public var headerTitle: String?
public var footerTitle: String?
var headerWillDisplayHandler: ZJTableViewSectionBlock?
public func setHeaderWillDisplayHandler(_ block: ZJTableViewSectionBlock?) {
headerWillDisplayHandler = block
}
var headerDidEndDisplayHandler: ZJTableViewSectionBlock?
public func setHeaderDidEndDisplayHandler(_ block: ZJTableViewSectionBlock?) {
headerDidEndDisplayHandler = block
}
public var index: Int {
return tableViewManager.sections.zj_indexOf(self)
}
override public init() {
super.init()
items = []
headerHeight = CGFloat.leastNormalMagnitude
footerHeight = CGFloat.leastNormalMagnitude
}
public convenience init(headerHeight: CGFloat!, color: UIColor) {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: headerHeight))
headerView.backgroundColor = color
self.init(headerView: headerView, footerView: nil)
}
public convenience init(headerTitle: String?, footerTitle: String?) {
self.init()
self.headerTitle = headerTitle
self.footerTitle = footerTitle
}
public convenience init(headerTitle: String?) {
self.init(headerTitle: headerTitle, footerTitle: nil)
}
public convenience init(footerTitle: String?) {
self.init(headerTitle: nil, footerTitle: footerTitle)
}
public convenience init(headerView: UIView!) {
self.init(headerView: headerView, footerView: nil)
}
public convenience init(footerView: UIView?) {
self.init(headerView: nil, footerView: footerView)
}
public convenience init(headerView: UIView?, footerView: UIView?) {
self.init()
if let header = headerView {
self.headerView = header
headerHeight = header.frame.size.height
}
if let footer = footerView {
self.footerView = footer
footerHeight = footer.frame.size.height
}
}
public func add(item: ZJTableViewItem) {
item.section = self
items.append(item)
}
public func remove(item: ZJTableViewItem) {
// If crash at here, item not in this section
items.remove(at: items.zj_indexOf(item))
}
public func removeAllItems() {
items.removeAll()
}
public func replaceItemsFrom(array: [ZJTableViewItem]!) {
removeAllItems()
items = items + array
}
public func insert(_ item: ZJTableViewItem!, afterItem: ZJTableViewItem, animate: UITableView.RowAnimation = .automatic) {
if !items.contains(where: { $0 == afterItem }) {
zj_log("can't insert because afterItem did not in sections")
return
}
tableViewManager.tableView.beginUpdates()
item.section = self
items.insert(item, at: items.zj_indexOf(afterItem) + 1)
tableViewManager.tableView.insertRows(at: [item.indexPath], with: animate)
tableViewManager.tableView.endUpdates()
}
public func insert(_ items: [ZJTableViewItem], afterItem: ZJTableViewItem, animate: UITableView.RowAnimation = .automatic) {
if !self.items.contains(where: { $0 == afterItem }) {
zj_log("can't insert because afterItem did not in sections")
return
}
tableViewManager.tableView.beginUpdates()
let newFirstIndex = self.items.zj_indexOf(afterItem) + 1
self.items.insert(contentsOf: items, at: newFirstIndex)
var arrNewIndexPath = [IndexPath]()
for i in 0 ..< items.count {
items[i].section = self
arrNewIndexPath.append(IndexPath(item: newFirstIndex + i, section: afterItem.indexPath.section))
}
tableViewManager.tableView.insertRows(at: arrNewIndexPath, with: animate)
tableViewManager.tableView.endUpdates()
}
public func delete(_ itemsToDelete: [ZJTableViewItem], animate: UITableView.RowAnimation = .automatic) {
guard itemsToDelete.count > 0 else { return }
tableViewManager.tableView.beginUpdates()
var arrNewIndexPath = [IndexPath]()
for i in itemsToDelete {
arrNewIndexPath.append(i.indexPath)
}
for i in itemsToDelete {
remove(item: i)
}
tableViewManager.tableView.deleteRows(at: arrNewIndexPath, with: animate)
tableViewManager.tableView.endUpdates()
}
public func reload(_ animation: UITableView.RowAnimation) {
// If crash at here, section did not in manager!
let index = tableViewManager.sections.zj_indexOf(self)
tableViewManager.tableView.reloadSections(IndexSet(integer: index), with: animation)
}
deinit {
print("Section Deinit")
}
}
//
// ZJExpandTreeCell.swift
// ZJExpandTreeDeme
//
// Created by Javen on 2019/3/19.
// Copyright © 2019 Javen. All rights reserved.
// https://www.jianshu.com/p/49ed18a01f19
import UIKit
open class ZJExpandTreeCellItem: ZJTableViewItem {
public private(set) var level: Int = 0
public var isExpand = false
public var arrSubLevel = [ZJExpandTreeCellItem]()
/// 展开或者收起下级cell的回调
public var willExpand: ((ZJExpandTreeCellItem) -> Void)?
public weak var superLevelItem: ZJExpandTreeCellItem?
/// 折叠时是否保持下级的树形结构
public var isKeepStructure = true
/// 是否自动折叠已经打开的Cell
public var isAutoClose = false
override public init() {
super.init()
selectionStyle = .none
setSelectionHandler { [unowned self] (callBackItem: ZJExpandTreeCellItem) in
if let superLevelItem = self.superLevelItem, superLevelItem.isAutoClose {
// 寻找同级已经展开的item
let arrItems = superLevelItem.getAllBelowItems().filter { $0.level == self.level && $0 != self && $0.isExpand }
for item in arrItems {
item.toggleExpand()
}
}
callBackItem.toggleExpand()
}
}
public func addSub(item: ZJExpandTreeCellItem, section: ZJTableViewSection) {
arrSubLevel.append(item)
item.superLevelItem = self
item.level = level + 1
if ZJExpandTreeCellItem.checkIfFoldedBySupperLevel(self), isExpand {
section.add(item: item)
}
}
/// 处理展开事件,返回值是当前cell的状态(展开或者收起)
@discardableResult open func toggleExpand() -> Bool {
var arrItems: [ZJExpandTreeCellItem]
if isExpand {
// 点击之前是打开的,直接通过递归获取item
arrItems = getAllBelowItems()
isExpand = !isExpand
} else {
// 点击之前是关闭的,需要先改变isExpand属性(不这么做会导致这一个level下一级的cell不显示)
isExpand = !isExpand
arrItems = getAllBelowItems()
if !isKeepStructure {
var tempItems = [ZJExpandTreeCellItem]()
for item in arrItems {
item.isExpand = false
if item.level == level + 1 {
tempItems.append(item)
}
}
arrItems = tempItems
}
}
willExpand?(self)
if isExpand {
section.insert(arrItems, afterItem: self, animate: .fade)
} else {
section.delete(arrItems, animate: .fade)
}
zj_log(isExpand ? "展开" : "收起")
return isExpand
}
/// 获取当前item下面所有的item
public func getAllBelowItems() -> [ZJExpandTreeCellItem] {
var arrItems = [ZJExpandTreeCellItem]()
ZJExpandTreeCellItem.recursionForItem(self, outItems: &arrItems)
return arrItems
}
/// 递归获取一个item下面所有显示的item
public class func recursionForItem(_ item: ZJExpandTreeCellItem, outItems: inout [ZJExpandTreeCellItem]) {
for subItem in item.arrSubLevel {
zj_log(subItem.level)
if item.isExpand == true {
outItems.append(subItem)
if item.arrSubLevel.count != 0 {
recursionForItem(subItem, outItems: &outItems)
}
}
}
}
// 递归判断一个item是否在某个父节点被折叠
public class func checkIfFoldedBySupperLevel(_ item: ZJExpandTreeCellItem) -> Bool {
guard let superItem = item.superLevelItem else {
return item.isExpand
}
if superItem.isExpand {
return checkIfFoldedBySupperLevel(superItem)
} else {
return false
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment