├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
└── ZYColumnViewDemo
├── .DS_Store
├── ZYColumnViewDemo.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
└── ZYColumnViewDemo
├── .DS_Store
├── AppDelegate.swift
├── Assets.xcassets
└── AppIcon.appiconset
│ └── Contents.json
├── Base.lproj
└── LaunchScreen.storyboard
├── Info.plist
├── Introduce
└── column.gif
├── OC-ZYColumnViewController.zip
├── ViewController.swift
└── ZYColumnView
├── .DS_Store
├── ZYColumnConfig.swift
├── ZYColumnDownPromptView.swift
├── ZYColumnHScrollView.swift
├── ZYColumnItem.swift
├── ZYColumnResource
├── column_edit_button@2x.png
├── column_edit_delete@2x.png
├── column_item_bg@2x.png
└── column_spread@2x.png
├── ZYColumnSpreadView.swift
├── ZYColumnUpPromptView.swift
└── ZYColumnViewController.swift
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | # Pods/
47 |
48 | # Carthage
49 | #
50 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
51 | # Carthage/Checkouts
52 |
53 | Carthage/Build
54 |
55 | # fastlane
56 | #
57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
58 | # screenshots whenever they are needed.
59 | # For more information about the recommended setup visit:
60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
61 |
62 | fastlane/report.xml
63 | fastlane/Preview.html
64 | fastlane/screenshots
65 | fastlane/test_output
66 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 r9ronaldozhang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ZYColumnViewController
2 | 仿网易新闻 频道选择器 支持swift3.0 简单易用 编译测试 XCode 8.0 XCode8.1
3 |
4 | ## 关于 ZYColumnViewController
5 | * ZYColumnViewController是一款简单易用的轻量级频道选择控件,其UI界面参考网易新闻。但是我为用户留下大量的可定制DIY常量供使用者修改以满足各自项目的实际需求
6 |
7 | ## 支持版本
8 | * 目前此控件尽支持swift3.0 已经在XCode8.0以及XCode8.1上进行了编译测试。需要OC版本或者支持swift2.3的可以issues我
9 |
10 | ## OC 版本已经加入
11 | * 看来还是有不少OC的死忠,已经上传了OC版本,花了1个小时调试...
12 | * 解压包内的压缩文件,就是OC的DEMO,源文件使用跟swift的一致,详见DEMO
13 |
14 | ## 如何使用
15 | * 下载
16 | * 本控件暂时不支持cocoapods 需要下载到本地
17 | * 集成和使用
18 | * 控件的内容存在于演示Demo中,将整个ZYColumnView 文件夹内的文件拖拽到你的项目中即可,无其他的任何依赖
19 | * ZYColumnViewController 力求最精简的API 让用户不需要关注太多 用户只需要按照Demo中的方法初始化,并且设置代理以后即可通过三个代理方法拿到你需要的一切回调
20 | * 如果你不需要下面的indicator指示条,可以进行简单处理,在配置文件中,将高度调整为0,或者将颜色设置为透明即可
21 | * 你需要关注的
22 | * 面向你的是 ZYColumnViewController 里面的三个属性 以及三个代理方法
23 | * DIY 保证你的项目能达到你想要的效果,去ZYColumnConfig 里面去捣腾吧!
24 |
25 | ## 效果图
26 |
27 | ** gif 易挂 复制链接到浏览器看效果 http://www.code4app.com/data/attachment/forum/201610/30/141214iw12tueoo9ex9x2e.gif
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/.DS_Store
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 79C4B9731DC3A6600047EF23 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9721DC3A6600047EF23 /* AppDelegate.swift */; };
11 | 79C4B9751DC3A6600047EF23 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9741DC3A6600047EF23 /* ViewController.swift */; };
12 | 79C4B97A1DC3A6600047EF23 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79C4B9791DC3A6600047EF23 /* Assets.xcassets */; };
13 | 79C4B97D1DC3A6600047EF23 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 79C4B97B1DC3A6600047EF23 /* LaunchScreen.storyboard */; };
14 | 79C4B9911DC3A69B0047EF23 /* ZYColumnConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9851DC3A69B0047EF23 /* ZYColumnConfig.swift */; };
15 | 79C4B9921DC3A69B0047EF23 /* ZYColumnDownPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9861DC3A69B0047EF23 /* ZYColumnDownPromptView.swift */; };
16 | 79C4B9931DC3A69B0047EF23 /* ZYColumnHScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9871DC3A69B0047EF23 /* ZYColumnHScrollView.swift */; };
17 | 79C4B9941DC3A69B0047EF23 /* ZYColumnItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9881DC3A69B0047EF23 /* ZYColumnItem.swift */; };
18 | 79C4B9951DC3A69B0047EF23 /* column_edit_button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 79C4B98A1DC3A69B0047EF23 /* column_edit_button@2x.png */; };
19 | 79C4B9961DC3A69B0047EF23 /* column_edit_delete@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 79C4B98B1DC3A69B0047EF23 /* column_edit_delete@2x.png */; };
20 | 79C4B9971DC3A69B0047EF23 /* column_item_bg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 79C4B98C1DC3A69B0047EF23 /* column_item_bg@2x.png */; };
21 | 79C4B9981DC3A69B0047EF23 /* column_spread@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 79C4B98D1DC3A69B0047EF23 /* column_spread@2x.png */; };
22 | 79C4B9991DC3A69B0047EF23 /* ZYColumnSpreadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B98E1DC3A69B0047EF23 /* ZYColumnSpreadView.swift */; };
23 | 79C4B99A1DC3A69B0047EF23 /* ZYColumnUpPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B98F1DC3A69B0047EF23 /* ZYColumnUpPromptView.swift */; };
24 | 79C4B99B1DC3A69B0047EF23 /* ZYColumnViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B9901DC3A69B0047EF23 /* ZYColumnViewController.swift */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXFileReference section */
28 | 79C4B96F1DC3A6600047EF23 /* ZYColumnViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZYColumnViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
29 | 79C4B9721DC3A6600047EF23 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
30 | 79C4B9741DC3A6600047EF23 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
31 | 79C4B9791DC3A6600047EF23 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
32 | 79C4B97C1DC3A6600047EF23 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
33 | 79C4B97E1DC3A6600047EF23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | 79C4B9851DC3A69B0047EF23 /* ZYColumnConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnConfig.swift; sourceTree = ""; };
35 | 79C4B9861DC3A69B0047EF23 /* ZYColumnDownPromptView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnDownPromptView.swift; sourceTree = ""; };
36 | 79C4B9871DC3A69B0047EF23 /* ZYColumnHScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnHScrollView.swift; sourceTree = ""; };
37 | 79C4B9881DC3A69B0047EF23 /* ZYColumnItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnItem.swift; sourceTree = ""; };
38 | 79C4B98A1DC3A69B0047EF23 /* column_edit_button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "column_edit_button@2x.png"; sourceTree = ""; };
39 | 79C4B98B1DC3A69B0047EF23 /* column_edit_delete@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "column_edit_delete@2x.png"; sourceTree = ""; };
40 | 79C4B98C1DC3A69B0047EF23 /* column_item_bg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "column_item_bg@2x.png"; sourceTree = ""; };
41 | 79C4B98D1DC3A69B0047EF23 /* column_spread@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "column_spread@2x.png"; sourceTree = ""; };
42 | 79C4B98E1DC3A69B0047EF23 /* ZYColumnSpreadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnSpreadView.swift; sourceTree = ""; };
43 | 79C4B98F1DC3A69B0047EF23 /* ZYColumnUpPromptView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnUpPromptView.swift; sourceTree = ""; };
44 | 79C4B9901DC3A69B0047EF23 /* ZYColumnViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZYColumnViewController.swift; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 79C4B96C1DC3A6600047EF23 /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 79C4B9661DC3A6600047EF23 = {
59 | isa = PBXGroup;
60 | children = (
61 | 79C4B9711DC3A6600047EF23 /* ZYColumnViewDemo */,
62 | 79C4B9701DC3A6600047EF23 /* Products */,
63 | );
64 | sourceTree = "";
65 | };
66 | 79C4B9701DC3A6600047EF23 /* Products */ = {
67 | isa = PBXGroup;
68 | children = (
69 | 79C4B96F1DC3A6600047EF23 /* ZYColumnViewDemo.app */,
70 | );
71 | name = Products;
72 | sourceTree = "";
73 | };
74 | 79C4B9711DC3A6600047EF23 /* ZYColumnViewDemo */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 79C4B9841DC3A69B0047EF23 /* ZYColumnView */,
78 | 79C4B9721DC3A6600047EF23 /* AppDelegate.swift */,
79 | 79C4B9741DC3A6600047EF23 /* ViewController.swift */,
80 | 79C4B9791DC3A6600047EF23 /* Assets.xcassets */,
81 | 79C4B97B1DC3A6600047EF23 /* LaunchScreen.storyboard */,
82 | 79C4B97E1DC3A6600047EF23 /* Info.plist */,
83 | );
84 | path = ZYColumnViewDemo;
85 | sourceTree = "";
86 | };
87 | 79C4B9841DC3A69B0047EF23 /* ZYColumnView */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 79C4B9851DC3A69B0047EF23 /* ZYColumnConfig.swift */,
91 | 79C4B9861DC3A69B0047EF23 /* ZYColumnDownPromptView.swift */,
92 | 79C4B9871DC3A69B0047EF23 /* ZYColumnHScrollView.swift */,
93 | 79C4B9881DC3A69B0047EF23 /* ZYColumnItem.swift */,
94 | 79C4B9891DC3A69B0047EF23 /* ZYColumnResource */,
95 | 79C4B98E1DC3A69B0047EF23 /* ZYColumnSpreadView.swift */,
96 | 79C4B98F1DC3A69B0047EF23 /* ZYColumnUpPromptView.swift */,
97 | 79C4B9901DC3A69B0047EF23 /* ZYColumnViewController.swift */,
98 | );
99 | path = ZYColumnView;
100 | sourceTree = "";
101 | };
102 | 79C4B9891DC3A69B0047EF23 /* ZYColumnResource */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 79C4B98A1DC3A69B0047EF23 /* column_edit_button@2x.png */,
106 | 79C4B98B1DC3A69B0047EF23 /* column_edit_delete@2x.png */,
107 | 79C4B98C1DC3A69B0047EF23 /* column_item_bg@2x.png */,
108 | 79C4B98D1DC3A69B0047EF23 /* column_spread@2x.png */,
109 | );
110 | path = ZYColumnResource;
111 | sourceTree = "";
112 | };
113 | /* End PBXGroup section */
114 |
115 | /* Begin PBXNativeTarget section */
116 | 79C4B96E1DC3A6600047EF23 /* ZYColumnViewDemo */ = {
117 | isa = PBXNativeTarget;
118 | buildConfigurationList = 79C4B9811DC3A6600047EF23 /* Build configuration list for PBXNativeTarget "ZYColumnViewDemo" */;
119 | buildPhases = (
120 | 79C4B96B1DC3A6600047EF23 /* Sources */,
121 | 79C4B96C1DC3A6600047EF23 /* Frameworks */,
122 | 79C4B96D1DC3A6600047EF23 /* Resources */,
123 | );
124 | buildRules = (
125 | );
126 | dependencies = (
127 | );
128 | name = ZYColumnViewDemo;
129 | productName = ZYColumnViewDemo;
130 | productReference = 79C4B96F1DC3A6600047EF23 /* ZYColumnViewDemo.app */;
131 | productType = "com.apple.product-type.application";
132 | };
133 | /* End PBXNativeTarget section */
134 |
135 | /* Begin PBXProject section */
136 | 79C4B9671DC3A6600047EF23 /* Project object */ = {
137 | isa = PBXProject;
138 | attributes = {
139 | LastSwiftUpdateCheck = 0800;
140 | LastUpgradeCheck = 0910;
141 | ORGANIZATIONNAME = "成都拓尔思";
142 | TargetAttributes = {
143 | 79C4B96E1DC3A6600047EF23 = {
144 | CreatedOnToolsVersion = 8.0;
145 | LastSwiftMigration = 0910;
146 | ProvisioningStyle = Automatic;
147 | };
148 | };
149 | };
150 | buildConfigurationList = 79C4B96A1DC3A6600047EF23 /* Build configuration list for PBXProject "ZYColumnViewDemo" */;
151 | compatibilityVersion = "Xcode 3.2";
152 | developmentRegion = English;
153 | hasScannedForEncodings = 0;
154 | knownRegions = (
155 | en,
156 | Base,
157 | );
158 | mainGroup = 79C4B9661DC3A6600047EF23;
159 | productRefGroup = 79C4B9701DC3A6600047EF23 /* Products */;
160 | projectDirPath = "";
161 | projectRoot = "";
162 | targets = (
163 | 79C4B96E1DC3A6600047EF23 /* ZYColumnViewDemo */,
164 | );
165 | };
166 | /* End PBXProject section */
167 |
168 | /* Begin PBXResourcesBuildPhase section */
169 | 79C4B96D1DC3A6600047EF23 /* Resources */ = {
170 | isa = PBXResourcesBuildPhase;
171 | buildActionMask = 2147483647;
172 | files = (
173 | 79C4B9971DC3A69B0047EF23 /* column_item_bg@2x.png in Resources */,
174 | 79C4B9961DC3A69B0047EF23 /* column_edit_delete@2x.png in Resources */,
175 | 79C4B9951DC3A69B0047EF23 /* column_edit_button@2x.png in Resources */,
176 | 79C4B97D1DC3A6600047EF23 /* LaunchScreen.storyboard in Resources */,
177 | 79C4B97A1DC3A6600047EF23 /* Assets.xcassets in Resources */,
178 | 79C4B9981DC3A69B0047EF23 /* column_spread@2x.png in Resources */,
179 | );
180 | runOnlyForDeploymentPostprocessing = 0;
181 | };
182 | /* End PBXResourcesBuildPhase section */
183 |
184 | /* Begin PBXSourcesBuildPhase section */
185 | 79C4B96B1DC3A6600047EF23 /* Sources */ = {
186 | isa = PBXSourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 79C4B99B1DC3A69B0047EF23 /* ZYColumnViewController.swift in Sources */,
190 | 79C4B99A1DC3A69B0047EF23 /* ZYColumnUpPromptView.swift in Sources */,
191 | 79C4B9751DC3A6600047EF23 /* ViewController.swift in Sources */,
192 | 79C4B9941DC3A69B0047EF23 /* ZYColumnItem.swift in Sources */,
193 | 79C4B9921DC3A69B0047EF23 /* ZYColumnDownPromptView.swift in Sources */,
194 | 79C4B9931DC3A69B0047EF23 /* ZYColumnHScrollView.swift in Sources */,
195 | 79C4B9991DC3A69B0047EF23 /* ZYColumnSpreadView.swift in Sources */,
196 | 79C4B9911DC3A69B0047EF23 /* ZYColumnConfig.swift in Sources */,
197 | 79C4B9731DC3A6600047EF23 /* AppDelegate.swift in Sources */,
198 | );
199 | runOnlyForDeploymentPostprocessing = 0;
200 | };
201 | /* End PBXSourcesBuildPhase section */
202 |
203 | /* Begin PBXVariantGroup section */
204 | 79C4B97B1DC3A6600047EF23 /* LaunchScreen.storyboard */ = {
205 | isa = PBXVariantGroup;
206 | children = (
207 | 79C4B97C1DC3A6600047EF23 /* Base */,
208 | );
209 | name = LaunchScreen.storyboard;
210 | sourceTree = "";
211 | };
212 | /* End PBXVariantGroup section */
213 |
214 | /* Begin XCBuildConfiguration section */
215 | 79C4B97F1DC3A6600047EF23 /* Debug */ = {
216 | isa = XCBuildConfiguration;
217 | buildSettings = {
218 | ALWAYS_SEARCH_USER_PATHS = NO;
219 | CLANG_ANALYZER_NONNULL = YES;
220 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
221 | CLANG_CXX_LIBRARY = "libc++";
222 | CLANG_ENABLE_MODULES = YES;
223 | CLANG_ENABLE_OBJC_ARC = YES;
224 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
225 | CLANG_WARN_BOOL_CONVERSION = YES;
226 | CLANG_WARN_COMMA = YES;
227 | CLANG_WARN_CONSTANT_CONVERSION = YES;
228 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
229 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
230 | CLANG_WARN_EMPTY_BODY = YES;
231 | CLANG_WARN_ENUM_CONVERSION = YES;
232 | CLANG_WARN_INFINITE_RECURSION = YES;
233 | CLANG_WARN_INT_CONVERSION = YES;
234 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
235 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
237 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
238 | CLANG_WARN_STRICT_PROTOTYPES = YES;
239 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
240 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
241 | CLANG_WARN_UNREACHABLE_CODE = YES;
242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
243 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
244 | COPY_PHASE_STRIP = NO;
245 | DEBUG_INFORMATION_FORMAT = dwarf;
246 | ENABLE_STRICT_OBJC_MSGSEND = YES;
247 | ENABLE_TESTABILITY = YES;
248 | GCC_C_LANGUAGE_STANDARD = gnu99;
249 | GCC_DYNAMIC_NO_PIC = NO;
250 | GCC_NO_COMMON_BLOCKS = YES;
251 | GCC_OPTIMIZATION_LEVEL = 0;
252 | GCC_PREPROCESSOR_DEFINITIONS = (
253 | "DEBUG=1",
254 | "$(inherited)",
255 | );
256 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
257 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
258 | GCC_WARN_UNDECLARED_SELECTOR = YES;
259 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
260 | GCC_WARN_UNUSED_FUNCTION = YES;
261 | GCC_WARN_UNUSED_VARIABLE = YES;
262 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
263 | MTL_ENABLE_DEBUG_INFO = YES;
264 | ONLY_ACTIVE_ARCH = YES;
265 | SDKROOT = iphoneos;
266 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
267 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
268 | };
269 | name = Debug;
270 | };
271 | 79C4B9801DC3A6600047EF23 /* Release */ = {
272 | isa = XCBuildConfiguration;
273 | buildSettings = {
274 | ALWAYS_SEARCH_USER_PATHS = NO;
275 | CLANG_ANALYZER_NONNULL = YES;
276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
277 | CLANG_CXX_LIBRARY = "libc++";
278 | CLANG_ENABLE_MODULES = YES;
279 | CLANG_ENABLE_OBJC_ARC = YES;
280 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
281 | CLANG_WARN_BOOL_CONVERSION = YES;
282 | CLANG_WARN_COMMA = YES;
283 | CLANG_WARN_CONSTANT_CONVERSION = YES;
284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
285 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
286 | CLANG_WARN_EMPTY_BODY = YES;
287 | CLANG_WARN_ENUM_CONVERSION = YES;
288 | CLANG_WARN_INFINITE_RECURSION = YES;
289 | CLANG_WARN_INT_CONVERSION = YES;
290 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
291 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
292 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
293 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
294 | CLANG_WARN_STRICT_PROTOTYPES = YES;
295 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
296 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
297 | CLANG_WARN_UNREACHABLE_CODE = YES;
298 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
299 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
300 | COPY_PHASE_STRIP = NO;
301 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
302 | ENABLE_NS_ASSERTIONS = NO;
303 | ENABLE_STRICT_OBJC_MSGSEND = YES;
304 | GCC_C_LANGUAGE_STANDARD = gnu99;
305 | GCC_NO_COMMON_BLOCKS = YES;
306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
307 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
308 | GCC_WARN_UNDECLARED_SELECTOR = YES;
309 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
310 | GCC_WARN_UNUSED_FUNCTION = YES;
311 | GCC_WARN_UNUSED_VARIABLE = YES;
312 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
313 | MTL_ENABLE_DEBUG_INFO = NO;
314 | SDKROOT = iphoneos;
315 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
316 | VALIDATE_PRODUCT = YES;
317 | };
318 | name = Release;
319 | };
320 | 79C4B9821DC3A6600047EF23 /* Debug */ = {
321 | isa = XCBuildConfiguration;
322 | buildSettings = {
323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
324 | INFOPLIST_FILE = ZYColumnViewDemo/Info.plist;
325 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
326 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
327 | PRODUCT_BUNDLE_IDENTIFIER = com.trs.test.ZYColumnViewDemo;
328 | PRODUCT_NAME = "$(TARGET_NAME)";
329 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
330 | SWIFT_VERSION = 4.0;
331 | };
332 | name = Debug;
333 | };
334 | 79C4B9831DC3A6600047EF23 /* Release */ = {
335 | isa = XCBuildConfiguration;
336 | buildSettings = {
337 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
338 | INFOPLIST_FILE = ZYColumnViewDemo/Info.plist;
339 | IPHONEOS_DEPLOYMENT_TARGET = 10.2;
340 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
341 | PRODUCT_BUNDLE_IDENTIFIER = com.trs.test.ZYColumnViewDemo;
342 | PRODUCT_NAME = "$(TARGET_NAME)";
343 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
344 | SWIFT_VERSION = 4.0;
345 | };
346 | name = Release;
347 | };
348 | /* End XCBuildConfiguration section */
349 |
350 | /* Begin XCConfigurationList section */
351 | 79C4B96A1DC3A6600047EF23 /* Build configuration list for PBXProject "ZYColumnViewDemo" */ = {
352 | isa = XCConfigurationList;
353 | buildConfigurations = (
354 | 79C4B97F1DC3A6600047EF23 /* Debug */,
355 | 79C4B9801DC3A6600047EF23 /* Release */,
356 | );
357 | defaultConfigurationIsVisible = 0;
358 | defaultConfigurationName = Release;
359 | };
360 | 79C4B9811DC3A6600047EF23 /* Build configuration list for PBXNativeTarget "ZYColumnViewDemo" */ = {
361 | isa = XCConfigurationList;
362 | buildConfigurations = (
363 | 79C4B9821DC3A6600047EF23 /* Debug */,
364 | 79C4B9831DC3A6600047EF23 /* Release */,
365 | );
366 | defaultConfigurationIsVisible = 0;
367 | defaultConfigurationName = Release;
368 | };
369 | /* End XCConfigurationList section */
370 | };
371 | rootObject = 79C4B9671DC3A6600047EF23 /* Project object */;
372 | }
373 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/.DS_Store
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ZYColumnViewDemo
4 | //
5 | // Created by 张宇 on 2016/10/28.
6 | // Copyright © 2016年 成都拓尔思. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 |
19 | window = UIWindow(frame: UIScreen.main.bounds)
20 | let navVC = UINavigationController(rootViewController: ViewController())
21 | let tbVC = UITabBarController()
22 | tbVC.addChildViewController(navVC)
23 | tbVC.title = "首页"
24 | window?.rootViewController = tbVC
25 | window?.makeKeyAndVisible()
26 | return true
27 | }
28 |
29 | func applicationWillResignActive(_ application: UIApplication) {
30 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
31 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
32 | }
33 |
34 | func applicationDidEnterBackground(_ application: UIApplication) {
35 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
36 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
37 | }
38 |
39 | func applicationWillEnterForeground(_ application: UIApplication) {
40 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
41 | }
42 |
43 | func applicationDidBecomeActive(_ application: UIApplication) {
44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
45 | }
46 |
47 | func applicationWillTerminate(_ application: UIApplication) {
48 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/Introduce/column.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/Introduce/column.gif
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/OC-ZYColumnViewController.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/OC-ZYColumnViewController.zip
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ZYColumnViewDemo
4 | //
5 | // Created by 张宇 on 2016/10/28.
6 | // Copyright © 2016年 成都拓尔思. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController , ZYColumnViewControllerDelegate {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | view.backgroundColor = UIColor.gray
17 |
18 | // 注意,如果frame 位置,显示出现问题,尝试设置这个属性
19 | self.automaticallyAdjustsScrollViewInsets = false
20 |
21 | // 注意,arrayTitles 不能为空
22 | let arrayTitles = ["头条","财经","体育","娱乐圈","段子","健康","图片","军事","精选","国际足球","历史","跟帖","居家"]
23 | let arraySpareTitles = ["房产","直播","轻松一刻","独家","社会","手机","数码","酒香","美女","艺术","读书","情感","论坛","博客","NBA","旅游","跑步","影视","政务","本地","汽车","公开课","游戏","独家","时尚","轻松一刻","社会","漫画"]
24 | self.initColumnVC(arrayTitles, arraySpareTitles, 1)
25 |
26 | }
27 |
28 | /// 使用: 将ZYColumnView 文件夹 拖拽到你的工程中,不需要添加任何的依赖
29 | /// 在ZYColumnConfig里面DIY 按照你需求调整UI
30 | /// 展开view 里面的 item 代码比较简单,修改Item样式 可以直接修改 ZYColumnItem ,不会影响代码逻辑功能
31 | /// 注意,应用默认在导航条位置有一个透明控件,加载到window上,以响应点击导航条,收回展开的操作 size :(屏幕宽度 :64)
32 | /// 创建 columnVC 就这几行代码,啥功能都有了
33 | private func initColumnVC(_ titles : [String], _ spareTitles : [String] , _ fixCount : Int){
34 | // 初始化columnVC
35 | let columnVC = ZYColumnViewController()
36 | columnVC.view.frame = CGRect(x: 0, y: 64, width: ZYScreenWidth, height: 40)
37 | columnVC.arrayTitles = titles
38 | if spareTitles.count > 0 {
39 | columnVC.arraySpareTitles = spareTitles
40 | }
41 | columnVC.fixedCount = fixCount
42 | columnVC.delegate = self
43 | view.addSubview(columnVC.view)
44 | addChildViewController(columnVC)
45 | }
46 |
47 | /// 三个代理方法,能够满足你需求的数据
48 | func columnViewControllerSetTitle(setTitle: String, index: Int) {
49 |
50 | }
51 |
52 | func columnViewControllerSelectedTitle(selectedTitle: String, index: Int) {
53 |
54 | }
55 |
56 | func columnViewControllerTitlesDidChanged(arrayTitles: [String]!, spareTitles: [String]?) {
57 |
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/.DS_Store
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnConfig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnConfig.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /******** 在此文件中定义了此控件常用的常用尺寸变量,用户可根据自己需求进行修改 ********/
12 |
13 | let kColumnScreenW = UIScreen.main.bounds.size.width
14 | let kColumnScreenH = UIScreen.main.bounds.size.height
15 |
16 | let kColumnItemEqualWidth = true // 默认横向item是否等宽 还是根据文字匹配
17 | let kColumnViewH:CGFloat = 40.0 // 默认高度
18 | let kColumnViewW = kColumnScreenW // 默认宽度
19 | let kSpreadMaxH:CGFloat = kColumnScreenH - 64 // 默认下拉展开的最大高度
20 | let kSpreadDuration = 0.4 // 动画展开收拢的时长
21 | let kColumnLayoutCount = 4 // 排序item 每行个数
22 | let kColumnItemH:CGFloat = (ZYinch55()) ? 40: 30 // item的高度
23 | let kColumnItemW:CGFloat = (ZYinch55()) ? 85: 70 // item的宽度
24 | let kColumnMarginW:CGFloat = (ZYScreenWidth-CGFloat(kColumnLayoutCount)*kColumnItemW)/CGFloat(kColumnLayoutCount+1) // item的横向间距
25 | let kColumnMarginH:CGFloat = (ZYinch55()) ? 20:((ZYinch47()) ? 20: 15) // item的纵向间距
26 | let kColumnEditBtnW:CGFloat = 60 // 排序删除按钮的宽度
27 | let kColumnEditBtnH:CGFloat = 36 // 排序删除按钮的高度
28 | let kColumnEditBtnFont:CGFloat = 10 // 排序删除按钮的字体
29 | let kColumnEditBtnNorTitle = "排序删除" // 排序删除普通状态文字
30 | let kColumnEditBtnSelTitle = "完成" // 排序删除选中状态文字
31 | let kColumnItemBorderColor = UIColor.red.cgColor // item的色环
32 | let kColumnItemColor = UIColor.red // item的文字颜色
33 |
34 | let kColumnTitleMargin:CGFloat = 8 // title按钮之间默认没有间距,这个值保证两个按钮的间距
35 | let kColumnTitleNorColor = UIColor.darkText // title普通状态颜色
36 | let kColumnTitleSelColor = UIColor.red // title选中状态颜色
37 | let kColumnTitleNorFont:CGFloat = (ZYinch47() || ZYinch55()) ? 14 : 13 // title普通状态字体
38 | let kColumnTitleSelFont:CGFloat = (ZYinch47() || ZYinch55()) ? 16 : 15 // title选中状态字体
39 | let kColumnHasIndicator = true // 默认有指示线条
40 | let kColumnIndictorH:CGFloat = 2.0 // 指示线条高度
41 | let kColumnIndictorMinW : CGFloat = 60 // 指示条默认最小宽度
42 | let kColumnIndicatorColor = UIColor.red // 默认使用系统风格颜色
43 |
44 | /************** 常量定义 ****************/
45 | /// 是否是3.5英寸屏
46 | func ZYinch35() -> Bool {
47 | return UIScreen.main.bounds.size.height == 480.0
48 | }
49 |
50 | /// 是否是4.0英寸屏
51 | func ZYinch40() -> Bool {
52 | return UIScreen.main.bounds.size.height == 568.0
53 | }
54 | /// 是否是4.7英寸屏
55 | func ZYinch47() -> Bool {
56 | return UIScreen.main.bounds.size.height == 667.0
57 | }
58 | /// 是否是5.5英寸屏
59 | func ZYinch55() -> Bool {
60 | return UIScreen.main.bounds.size.height == 736.0
61 | }
62 |
63 | let ZYScreenWidth = UIScreen.main.bounds.width
64 | let ZYScreenHeight = UIScreen.main.bounds.height
65 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnDownPromptView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnDownPromptView.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ZYColumnDownPromptView: UIView {
12 | override init(frame: CGRect) {
13 | super.init(frame: frame)
14 | // 初始化提示label
15 | let label = UILabel(frame:CGRect(x: kColumnMarginW, y: 0, width: 150, height: frame.height))
16 | label.text = "点击添加更多栏目"
17 | label.textColor = UIColor.darkGray
18 | addSubview(label)
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) {
22 | fatalError("init(coder:) has not been implemented")
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnHScrollView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnHScrollView.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | // 水平滚动的scrollView
8 |
9 | import UIKit
10 |
11 | typealias titleClickClosure = (_ tag: Int, _ title: String) -> Void
12 |
13 | class ZYColumnHScrollView: UIScrollView {
14 | // 闭包
15 | var backClosure : titleClickClosure? // 分类 标题数组
16 | var arrayTitles = [String]() {
17 | didSet {
18 | // 创建标题按钮item
19 | creatScrollItems()
20 | // 初始化自身属性 为了匹配indicator的宽度,这个方法后调用
21 | doInit()
22 | }
23 | }
24 | // 标识是否已经初始化过了
25 | fileprivate var hasInit = false
26 |
27 | // 记录选中的title button
28 | fileprivate var selButton = UIButton()
29 | // 指示器
30 | fileprivate var indicator = UIView()
31 | // 存放按钮的数组
32 | fileprivate var arrayItems = [UIButton]()
33 | }
34 |
35 | // MARK: - 初始化方法
36 | extension ZYColumnHScrollView {
37 | // 初始化一些属性
38 | fileprivate func doInit(){
39 | if hasInit {
40 | return
41 | }
42 | self.showsHorizontalScrollIndicator = false
43 | self.showsVerticalScrollIndicator = false
44 | guard kColumnHasIndicator else {return}
45 | let indicator = UIView(frame: CGRect(x:0, y: kColumnViewH - kColumnIndictorH, width: arrayItems[0].frame.width, height: kColumnIndictorH)) // 默认取第一个按钮的宽度
46 | self.indicator = indicator
47 | indicator.backgroundColor = kColumnIndicatorColor
48 | insertSubview(indicator, at: 0)
49 | addSubview(indicator)
50 | hasInit = true
51 | }
52 | }
53 |
54 | // MARK: - 点击事件处理
55 | extension ZYColumnHScrollView {
56 | @objc fileprivate func itemDidClick(button : UIButton) {
57 | // 切换选中item
58 | changeItemStatus(button: button)
59 |
60 | // 回调
61 | if self.backClosure != nil {
62 | self.backClosure!(button.tag, (button.titleLabel?.text)!)
63 | }
64 | }
65 | }
66 |
67 | // MARK: - 公共控制方法
68 | extension ZYColumnHScrollView {
69 |
70 | // 将对应的title的item设置为选中状态
71 | open func changeItemToSelected(title : String) {
72 | for item in arrayItems {
73 | if item.titleLabel?.text == title {
74 | changeItemStatus(button: item)
75 | return
76 | }
77 | }
78 | }
79 | }
80 |
81 | // MARK: - 私有控制方法
82 | extension ZYColumnHScrollView {
83 | // 添加横向滚动的item
84 | fileprivate func creatScrollItems(){
85 | // 先移除已经创建了的
86 | for item in arrayItems {
87 | item.removeFromSuperview()
88 | }
89 | arrayItems.removeAll()
90 |
91 | var sumItemW:CGFloat = 0.0
92 | for i in 0 ..< self.arrayTitles.count{
93 | let title = arrayTitles[i]
94 | let item = UIButton()
95 | item.setTitle(title, for: UIControlState.normal)
96 | item.sizeToFit()
97 | item.setTitleColor(kColumnTitleNorColor, for: UIControlState.normal)
98 | item.setTitleColor(kColumnTitleSelColor, for: UIControlState.selected)
99 | item.titleLabel?.font = UIFont.systemFont(ofSize: kColumnTitleNorFont)
100 | if kColumnItemEqualWidth {
101 | item.frame.size = CGSize(width: (kColumnScreenW-(CGFloat(kColumnLayoutCount)+1)*kColumnTitleMargin)/CGFloat(kColumnLayoutCount), height: kColumnHasIndicator ? kColumnViewH - kColumnIndictorH : kColumnViewH)
102 | } else {
103 | item.sizeToFit()
104 | item.frame.size = CGSize(width: (item.frame.width + kColumnTitleMargin) > kColumnIndictorMinW ? item.frame.width + kColumnTitleMargin : kColumnIndictorMinW, height: kColumnHasIndicator ? kColumnViewH - kColumnIndictorH : kColumnViewH) // 增加按钮宽度,达到间隙效果
105 | }
106 | item.frame = CGRect(x: sumItemW, y: 0, width: item.frame.width, height: item.frame.height)
107 | sumItemW += item.frame.width
108 | item.tag = i
109 | item.addTarget(self, action: #selector(self.itemDidClick(button:)), for: .touchUpInside)
110 | arrayItems.append(item)
111 | addSubview(item)
112 | contentSize = CGSize(width: sumItemW, height: 0)
113 | }
114 | }
115 |
116 | // 改变选中按钮状态
117 | fileprivate func changeItemStatus(button : UIButton) {
118 | selButton.titleLabel?.font = UIFont.systemFont(ofSize: kColumnTitleNorFont)
119 | selButton.isSelected = false
120 | button.titleLabel?.font = UIFont.systemFont(ofSize: kColumnTitleSelFont)
121 | button.isSelected = true
122 | selButton = button
123 | autoSuitItemsPosition()
124 | UIView.animate(withDuration: 0.3) { () -> Void in
125 | self.indicator.frame = CGRect(x: button.frame.origin.x, y: kColumnViewH - kColumnIndictorH, width: button.frame.width, height: kColumnIndictorH)
126 | }
127 | }
128 |
129 | // 自动匹配scrollView 的位置,让选中的置于中间位置
130 | private func autoSuitItemsPosition() {
131 | UIView.animate(withDuration: kSpreadDuration) {
132 | if self.contentSize.width > self.frame.size.width {
133 | var desiredX = self.selButton.center.x - self.bounds.width/2
134 | if desiredX < 0 {
135 | desiredX = 0
136 | }
137 | if desiredX > (self.contentSize.width - self.bounds.width) {
138 | desiredX = self.contentSize.width - self.bounds.width
139 | }
140 | if !(self.bounds.width > self.contentSize.width) {
141 | self.setContentOffset(CGPoint(x: desiredX, y: 0), animated: true)
142 | }
143 | }
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnItem.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | typealias delClickClosure = (_ item : ZYColumnItem) -> Void
12 |
13 | class ZYColumnItem: UIView {
14 | open var title : String!{
15 | didSet {
16 | doInit()
17 | }
18 | }
19 | // 标识是否是固定的,固定的item没有圆角,没有背景色效果的
20 | open var isFixed = false {
21 | didSet {
22 | if isFixed {
23 | setupFixedItem()
24 | }
25 | }
26 | }
27 |
28 | var delClosure : delClickClosure?
29 |
30 | var delBtn = UIButton()
31 |
32 | // 拉大item大小
33 | func scaleItemToLarge() {
34 | for item in subviews {
35 |
36 | if item.isKind(of: UIButton.self) && item.frame.width == self.frame.width {
37 | item.bounds = CGRect(x: 0, y: 0, width: self.frame.width * 1.2, height: self.frame.height * 1.2)
38 | }
39 | }
40 | }
41 | // 还原item大小
42 | func scaleItemToOriginal() {
43 | for item in subviews {
44 | if item.isKind(of: UIButton.self) && item.frame.width > self.frame.width {
45 | item.bounds = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
46 | }
47 | }
48 | }
49 |
50 | private func doInit(){
51 | // 添加按钮
52 | let item = UIButton()
53 | item.frame = CGRect(x:0 , y: 0, width:self.frame.width, height: self.frame.height)
54 | item.setTitle(title, for: .normal)
55 | item.setTitleColor(UIColor.darkGray, for: .normal)
56 | item.setBackgroundImage(UIImage(named: "column_item_bg.png"), for:.normal)
57 | item.isUserInteractionEnabled = false
58 | if ((title as NSString).length == 4) {
59 | item.titleLabel?.font = UIFont.systemFont(ofSize: 13)
60 | } else if ((title as NSString).length == 3) {
61 | item.titleLabel?.font = UIFont.systemFont(ofSize: 15)
62 | } else {
63 | item.titleLabel?.font = UIFont.systemFont(ofSize: 16)
64 | }
65 | self.addSubview(item)
66 | // 添加删除图标
67 | let WH = ZYinch55() ? 20 : (ZYinch47() ? 16 : 14)
68 | delBtn = UIButton(frame: CGRect(x: -1, y: -4, width: WH, height: WH))
69 | delBtn.setImage(UIImage(named: "column_edit_delete.png"), for: .normal)
70 | delBtn.addTarget(self, action: #selector(self.delBtnDidClick(delBtn:)), for: .touchUpInside)
71 | delBtn.isHidden = true
72 | addSubview(delBtn)
73 |
74 | }
75 |
76 | private func setupFixedItem() {
77 | for button in subviews {
78 | // 判断不是删除的按钮
79 | if button.frame.width == self.frame.width && button.isKind(of: UIButton.self) {
80 | let btn : UIButton = button as! UIButton
81 | btn.setBackgroundImage(nil, for: .normal)
82 | }
83 | }
84 | }
85 |
86 | @objc private func delBtnDidClick(delBtn : UIButton) {
87 | // 闭包传值
88 | if self.delClosure != nil {
89 | self.delClosure!(self)
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_edit_button@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_edit_button@2x.png
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_edit_delete@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_edit_delete@2x.png
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_item_bg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_item_bg@2x.png
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_spread@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r9ronaldozhang/ZYColumnViewController/cb8a7c396312af0aa4fdb430c2f45d24769e442a/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnResource/column_spread@2x.png
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnSpreadView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnSpreadView.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | // 上面item点击的闭包
11 | typealias upItemTapClosure = (_ item : ZYColumnItem) -> Void
12 |
13 | // 上面item长按的闭包
14 | typealias upItemLongPressClosure = () -> Void
15 |
16 | // 收起spreadView闭包
17 | typealias foldSpreadViewClosure = (_ upTitles : [String] , _ downTitles : [String]) -> Void
18 |
19 | class ZYColumnSpreadView: UIScrollView {
20 |
21 | // 上面的排序 标题 数组
22 | open var arrayUpTitles = [String]()
23 | // 下面的备选 标题 数组
24 | open var arrayDownTitles = [String]()
25 | // 固定不变的item个数
26 | open var fixedCount = 1
27 | // 标识当前是否排序状态
28 | open var isSortStatus = false
29 | // 上面item tap 的闭包
30 | open var tapClosure : upItemTapClosure?
31 | // 上面item长按闭包
32 | open var longPressClosure : upItemLongPressClosure?
33 | // 收起后的闭包
34 | open var flodClosure : foldSpreadViewClosure?
35 |
36 | /************* 上面是对外属性 -----华丽分割线----- 下面是私有属性 ***************/
37 |
38 | // 存放up items的数组
39 | fileprivate var arrayUpItems = [ZYColumnItem!]()
40 | // 存放down items 的数组
41 | fileprivate var arrayDownItems = [ZYColumnItem!]()
42 | // 拖动view的下一个view的中心点 逐个赋值
43 | fileprivate var valuePoint = CGPoint(x: 0, y: 0)
44 | // 用于赋值
45 | fileprivate var nextPoint = CGPoint(x: 0, y: 0)
46 | // 下提示view
47 | fileprivate lazy var downPromptView : ZYColumnDownPromptView = {
48 | let upLastItem = self.arrayUpItems.last
49 | let downView = ZYColumnDownPromptView(frame: CGRect(x: 0, y: upLastItem!.frame.maxY + kColumnMarginH, width: ZYScreenWidth, height: kColumnViewH))
50 | downView.backgroundColor = UIColor.init(red: 240.0/255, green: 241.0/255, blue: 246.0/255, alpha: 1.0)
51 | return downView
52 | }()
53 | }
54 |
55 | // MARK: - 公共方法
56 | extension ZYColumnSpreadView {
57 | /// 展开或者合拢
58 | open func doSpreadOrFold(toSpread : Bool , cover : UIView , upPromptView : UIView) {
59 | UIApplication.shared.keyWindow?.isUserInteractionEnabled = false
60 | UIView.animate(withDuration: kSpreadDuration, animations: { [weak self]() -> Void in
61 | self?.frame = CGRect(x: 0, y: 0, width: kColumnViewW, height: toSpread ? kSpreadMaxH : 0.0)
62 | }) {(_) -> Void in
63 | upPromptView.isHidden = toSpread ? false : true
64 | cover.isHidden = toSpread ? false : true
65 | UIApplication.shared.keyWindow?.isUserInteractionEnabled = true
66 | }
67 | // 添加items
68 | if toSpread && arrayUpItems.isEmpty {
69 | addItems()
70 | }
71 |
72 | // 闭包回传值
73 | if self.flodClosure != nil && !toSpread {
74 | // 同步数组顺序
75 | arrayUpTitles.removeAll()
76 | arrayDownTitles.removeAll()
77 | for i in 0 ..< arrayUpItems.count {
78 | let item = arrayUpItems[i]!
79 | arrayUpTitles.append(item.title)
80 | }
81 | for i in 0 ..< arrayDownItems.count {
82 | let item = arrayDownItems[i]!
83 | arrayDownTitles.append(item.title)
84 | }
85 | self.flodClosure!(arrayUpTitles, arrayDownTitles)
86 | }
87 | }
88 |
89 | /// 隐藏或者显示下面的item和downPromptView 参数传false 则变为 显示
90 | open func hideDownItemsAndPromptView(toHide : Bool) {
91 | if arrayDownItems.isEmpty { // 下面备选只要没有,一定不显示
92 | downPromptView.isHidden = true
93 | } else {
94 | downPromptView.isHidden = toHide
95 | }
96 | for i in 0 ..< arrayDownItems.count {
97 | let item : ZYColumnItem = arrayDownItems[i]
98 | item.isHidden = toHide
99 | }
100 | }
101 |
102 | /// 开启或者关闭排序按钮删除状态
103 | open func openDelStatus(showDel : Bool) {
104 | for i in 0 ..< arrayUpItems.count {
105 | let item : ZYColumnItem = arrayUpItems[i]
106 | if !item.isFixed {
107 | item.delBtn.isHidden = !showDel
108 | }
109 | }
110 | }
111 |
112 | /// 自动回滚到顶部
113 | open func scrollToTop() {
114 | var offect = self.contentOffset;
115 | offect.y = -self.contentInset.top;
116 | self.setContentOffset(offect, animated: false)
117 | }
118 | }
119 |
120 | // MARK: - 私有控制方法
121 | extension ZYColumnSpreadView {
122 | // 通过index 计算出上面item的frame
123 | fileprivate func getUpFrameWithIndex(_ index : Int) -> CGRect {
124 | let x = CGFloat(index%kColumnLayoutCount) * (kColumnMarginW + kColumnItemW) + kColumnMarginW
125 | let y = CGFloat(index/kColumnLayoutCount) * (kColumnMarginH + kColumnItemH) + kColumnMarginH + kColumnViewH
126 | let frame = CGRect(x: x, y: y, width: kColumnItemW, height: kColumnItemH)
127 | return frame
128 | }
129 | // 从下面移动到上面
130 | fileprivate func addItemToUp(item : ZYColumnItem) {
131 | let lastItem = arrayUpItems.last
132 | // 判断下面的item是否需要下移
133 | if (lastItem!.tag + 1) % kColumnLayoutCount == 0 {
134 | moveItemsRowDownOrUp(isUp: false)
135 | }
136 | let newFrame = getUpFrameWithIndex(lastItem!.tag + 1)
137 | UIView.animate(withDuration: kSpreadDuration, animations: {
138 | item.frame = newFrame
139 | }) { (_) in
140 | self.reSetContentSize()
141 | }
142 | }
143 | // 将arrayDownItems 的items 整体下移或者上移一行 包含downPromptView
144 | private func moveItemsRowDownOrUp(isUp : Bool) {
145 | let rowH = isUp ? -(kColumnItemH + kColumnMarginH) : (kColumnItemH + kColumnMarginH)
146 |
147 | downPromptView.frame = CGRect(x: downPromptView.frame.origin.x, y: downPromptView.frame.origin.y+rowH, width: downPromptView.frame.width, height: downPromptView.frame.height)
148 | for i in 0 ..< arrayDownItems.count {
149 | let item = arrayDownItems[i]!
150 | item.frame = CGRect(x: item.frame.origin.x, y: item.frame.origin.y+rowH, width: item.frame.width, height: item.frame.height)
151 | }
152 | }
153 | // 从上面删除 item插入到下面
154 | fileprivate func removeItemFromUp(item : ZYColumnItem) {
155 | item.delBtn.isHidden = true
156 | item.isHidden = true
157 | reLayoutUpItemsWithAnimation()
158 | reLayoutDownItemsWithAnimation(withAnimate: false)
159 | let lastItem = arrayUpItems.last
160 | if (lastItem!.tag + 1)%kColumnLayoutCount == 0 {
161 | moveItemsRowDownOrUp(isUp: true)
162 | }
163 | reSetContentSize()
164 | }
165 |
166 | fileprivate func synchronizeItemsTag() {
167 | var x = 0
168 | for i in 0 ..< arrayUpItems.count {
169 | let item = arrayUpItems[i]!
170 | item.tag = i
171 | x += 1
172 | }
173 |
174 | var j = x
175 | for y in 0 ..< arrayDownItems.count {
176 | let item = arrayDownItems[y]!
177 | item.tag = j
178 | j += 1
179 | }
180 | }
181 | // 重新计算最新的contentSize
182 | private func reSetContentSize() {
183 | let lastItem = arrayDownItems.isEmpty ? arrayUpItems.last : arrayDownItems.last
184 | self.contentSize = CGSize(width: 0, height: lastItem!.frame.maxY + kColumnMarginH)
185 | }
186 |
187 | // 点击后 动态排序上面的item
188 | private func reLayoutUpItemsWithAnimation(){
189 | for i in 0 ..< arrayUpItems.count {
190 | let item = arrayUpItems[i]!
191 | let newFrame = getUpFrameWithIndex(item.tag)
192 | UIView.animate(withDuration: kSpreadDuration, animations: {
193 | item.frame = newFrame
194 | })
195 | }
196 | }
197 | // 点击后 动态排序下面的item
198 | fileprivate func reLayoutDownItemsWithAnimation(withAnimate : Bool) {
199 | for i in 0 ..< arrayDownItems.count {
200 | let item = arrayDownItems[i]!
201 | let x = CGFloat((item.tag - arrayUpItems.count) % kColumnLayoutCount) * (kColumnMarginW + kColumnItemW) + kColumnMarginW
202 | let y = CGFloat((item.tag - arrayUpItems.count) / kColumnLayoutCount) * (kColumnMarginH + kColumnItemH) + kColumnMarginH + downPromptView.frame.maxY
203 | if withAnimate {
204 | UIView.animate(withDuration: kSpreadDuration, animations: {
205 | item.frame = CGRect(x: x, y: y, width: item.frame.width, height: item.frame.height)
206 | })
207 | } else {
208 | item.frame = CGRect(x: x, y: y, width: item.frame.width, height: item.frame.height)
209 | }
210 | }
211 | }
212 |
213 | // 删除图标点击闭包回调处理
214 | fileprivate func handleClosure (item : ZYColumnItem) {
215 | guard !item.isFixed else {
216 | return
217 | }
218 | // 从上面数组移除item 添加到下面数组
219 | arrayUpItems.remove(at: item.tag)
220 | arrayDownItems.insert(item, at: 0)
221 | synchronizeItemsTag()
222 | removeItemFromUp(item: item)
223 | }
224 | }
225 |
226 | // MARK: - 初始化 上 下 item 和 downPromptView
227 | extension ZYColumnSpreadView {
228 | fileprivate func addItems(){
229 | // 添加上面 items
230 |
231 | for i in 0 ..< arrayUpTitles.count {
232 | let item = ZYColumnItem(frame: getUpFrameWithIndex(i)) // 通过公共方法计算frame
233 | item.title = arrayUpTitles[i]
234 | item.tag = i
235 | if i < fixedCount {
236 | item.isFixed = true
237 | }
238 | // 闭包回调
239 | item.delClosure = {
240 | [weak self](item : ZYColumnItem) -> Void in
241 | self!.handleClosure(item: item)
242 | }
243 | // 添加长按手势
244 | addLongPressGesture(item: item)
245 |
246 | // 添加tap手势
247 | addTapGesture(item: item)
248 | addSubview(item)
249 | arrayUpItems.append(item)
250 | }
251 |
252 | let upLastItem = arrayUpItems.last
253 | // 添加下提示view
254 | insertSubview(downPromptView, at: 0)
255 | guard !arrayDownTitles.isEmpty else {
256 | // 下面没有备选 直接算出spreadView contentSize
257 | self.contentSize = CGSize(width: 0, height: upLastItem!.frame.maxY + kColumnMarginH + downPromptView.frame.height)
258 | return
259 | }
260 |
261 | // 添加下排序items
262 | for i in 0 ..< arrayDownTitles.count {
263 | let x = CGFloat(i%kColumnLayoutCount) * (kColumnMarginW + kColumnItemW) + kColumnMarginW
264 | let y = CGFloat(i/kColumnLayoutCount) * (kColumnMarginH + kColumnItemH) + kColumnMarginH + downPromptView.frame.maxY
265 | let item = ZYColumnItem(frame: CGRect(x: x, y: y, width: kColumnItemW, height: kColumnItemH))
266 | item.title = arrayDownTitles[i]
267 | item.tag = i + arrayUpItems.count
268 | // 添加长按手势
269 | addLongPressGesture(item: item)
270 | // 添加tap手势
271 | addTapGesture(item: item)
272 | // 闭包回调
273 | item.delClosure = {
274 | [weak self](item : ZYColumnItem) -> Void in
275 | self!.handleClosure(item: item)
276 | }
277 | addSubview(item)
278 | arrayDownItems.append(item)
279 | if i == arrayDownTitles.count - 1 {
280 | let downLastItem = arrayDownItems.last
281 | self.contentSize = CGSize(width: 0, height: downLastItem!.frame.maxY + kColumnMarginH)
282 | }
283 | }
284 | }
285 | }
286 |
287 | // MARK: - 手势绑定 与手势处理
288 | extension ZYColumnSpreadView {
289 | /// 为一个item绑定长按手势
290 | fileprivate func addLongPressGesture(item : ZYColumnItem) {
291 | let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.upItmesDidLongPress(longPress:)))
292 | item.addGestureRecognizer(longPressGesture)
293 | }
294 | /// item 长按手势处理
295 | @objc fileprivate func upItmesDidLongPress(longPress: UILongPressGestureRecognizer) {
296 | let item = longPress.view as! ZYColumnItem
297 | if item.isFixed { // 固定的item 不做处理
298 | return
299 | }
300 | // 只响应上面的item的长按事件
301 | for i in 0 ..< arrayUpItems.count {
302 | let element = arrayUpItems[i]
303 | if element == item {
304 | handleLongPressGesture(item: item, longPress: longPress)
305 | return
306 | }
307 | }
308 | }
309 |
310 | /// 为一个item绑定tap手势
311 | fileprivate func addTapGesture(item : ZYColumnItem) {
312 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.itemDidTap(tapGesture:)))
313 | item.addGestureRecognizer(tapGesture)
314 | }
315 | // item tap事件处理
316 | @objc fileprivate func itemDidTap(tapGesture : UITapGestureRecognizer) {
317 | let item = tapGesture.view as! ZYColumnItem
318 |
319 | // 点击的是上面的item 回传值
320 | for i in 0 ..< arrayUpItems.count {
321 | let element = arrayUpItems[i]
322 | if element == item {
323 | if isSortStatus {
324 | return
325 | }
326 | // 闭包传值
327 | if self.tapClosure != nil {
328 | self.tapClosure!(item)
329 | }
330 | return
331 | }
332 | }
333 | // 点击的是下面的item 上移
334 | for i in 0 ..< arrayDownItems.count {
335 | let element = arrayDownItems[i]
336 | if element == item {
337 | addItemToUp(item: item)
338 | arrayDownItems.remove(at: item.tag - arrayUpItems.count)
339 | arrayUpItems.append(item)
340 | synchronizeItemsTag()
341 | reLayoutDownItemsWithAnimation(withAnimate: true)
342 | if arrayDownItems.isEmpty { // 当最后一个item都上移了,下面的指示view 隐藏掉
343 | downPromptView.isHidden = true
344 | }
345 | return
346 | }
347 | }
348 | }
349 |
350 | private func handleLongPressGesture(item : ZYColumnItem, longPress : UILongPressGestureRecognizer) {
351 |
352 | // 拿到当前的最新位置
353 | let recognizerPoint = longPress.location(in: self)
354 |
355 | switch longPress.state {
356 | case UIGestureRecognizerState.began:
357 | // 如果没有显示“删除”按钮,回传闭包,开启删除排序模式
358 | if !isSortStatus {
359 | if longPressClosure != nil {
360 | longPressClosure!()
361 | }
362 | }
363 |
364 | // 禁用其他item的交互
365 | for i in 0 ..< arrayUpItems.count {
366 | let element = arrayUpItems[i]!
367 | if element != item {
368 | element.isUserInteractionEnabled = false
369 | }
370 | }
371 |
372 | self.bringSubview(toFront: item)
373 | valuePoint = item.center
374 | item.scaleItemToLarge()
375 | case UIGestureRecognizerState.changed:
376 | // 更新长按item的位置
377 | item.center = recognizerPoint
378 | // 判断item的center是否移动到了其他item的位置上了
379 | for i in 0 ..< arrayUpItems.count {
380 | let element = arrayUpItems[i]!
381 | if element.frame.contains(item.center) && element != item && element.tag >= fixedCount {
382 | // 开始位置索引
383 | let fromIndex = item.tag
384 | // 需要移动到的索引
385 | let toIndex = element.tag
386 | if toIndex > fromIndex { // 往后移
387 | // 把移动view的下一个view移动到记录的view的位置(valuePoint),并把下一view的位置记为新的nextPoint,并把view的tag值-1,依次类推
388 | UIView.animate(withDuration: kSpreadDuration, animations: {
389 | for i in fromIndex + 1 ... toIndex {
390 | let nextItem = self.viewWithTag(i) as! ZYColumnItem
391 | self.nextPoint = nextItem.center
392 | nextItem.center = self.valuePoint
393 | self.valuePoint = self.nextPoint
394 | nextItem.tag -= 1
395 | }
396 | item.tag = toIndex
397 | })
398 | } else { // 往前移
399 | // 把移动view的上一个view移动到记录的view的位置(valuePoint),并把上一view的位置记为新的nextPoint,并把view的tag值+1,依次类推
400 | UIView.animate(withDuration: kSpreadDuration, animations: {
401 | for i in (toIndex ... fromIndex - 1).reversed(){
402 | let nextItem = self.viewWithTag(i) as! ZYColumnItem
403 | self.nextPoint = nextItem.center
404 | nextItem.center = self.valuePoint
405 | self.valuePoint = self.nextPoint
406 | nextItem.tag += 1
407 | }
408 | item.tag = toIndex
409 | })
410 | }
411 | }
412 | }
413 | case UIGestureRecognizerState.ended:
414 | // 恢复其他item的交互
415 | for i in 0 ..< arrayUpItems.count {
416 | let element = arrayUpItems[i]!
417 | if element != item {
418 | element.isUserInteractionEnabled = true
419 | }
420 | }
421 | // 还原item的大小
422 | item.scaleItemToOriginal()
423 | // 返回对应的中心点
424 | UIView.animate(withDuration: kSpreadDuration, animations: {
425 | })
426 | UIView.animate(withDuration: kSpreadDuration, animations: {
427 | item.center = self.valuePoint
428 |
429 | }, completion: { [weak self](_) in
430 | // 同步数组
431 | var temp = [ZYColumnItem!]()
432 | for i in 0 ..< self!.arrayUpItems.count {
433 | for j in 0 ..< self!.arrayUpItems.count {
434 | let item = self!.arrayUpItems[j]!
435 | if item.tag == i {
436 | temp.append(item)
437 | break
438 | }
439 | }
440 | }
441 | self!.arrayUpItems = temp
442 | })
443 | default:
444 | break
445 | }
446 | }
447 | }
448 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnUpPromptView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnUpPromptView.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | typealias editBtnClickClosure = (_ isSelected : Bool) -> Void
12 |
13 | class ZYColumnUpPromptView: UIView {
14 |
15 | var editBtn : UIButton?
16 | // 编辑按钮回调闭包
17 | var clickClosure : editBtnClickClosure?
18 |
19 | override init(frame: CGRect) {
20 | super.init(frame:frame)
21 | // 初始化子控件
22 | let label = UILabel(frame: CGRect(x: kColumnMarginW, y: 0, width: 100, height: kColumnViewH))
23 | label.text = "栏目切换"
24 | label.textColor = UIColor.darkGray
25 | addSubview(label)
26 |
27 | // 切换状态按钮
28 | let editBtn = UIButton(frame: CGRect(x: kColumnViewW - kColumnViewH - kColumnEditBtnW - 10, y: (kColumnViewH - kColumnEditBtnH)*0.5, width: kColumnEditBtnW, height: kColumnEditBtnH))
29 | self.editBtn = editBtn
30 | editBtn.setTitle(kColumnEditBtnNorTitle, for: .normal)
31 | editBtn.setTitle(kColumnEditBtnSelTitle, for: .selected)
32 | editBtn.setBackgroundImage(UIImage(named:"column_edit_button"), for: .normal)
33 | editBtn.setBackgroundImage(UIImage(named:"column_edit_button"), for: .highlighted)
34 | editBtn.titleLabel?.font = UIFont.systemFont(ofSize: kColumnEditBtnFont)
35 | editBtn.setTitleColor(kColumnItemColor, for: .normal)
36 | // editBtn.layer.borderWidth = 1.0
37 | // editBtn.layer.borderColor = kColumnItemBorderColor
38 | // editBtn.layer.cornerRadius = kColumnEditBtnH * 0.5
39 | editBtn.addTarget(self, action: #selector(self.editButtonClick(editBtn:)), for: .touchUpInside)
40 | addSubview(editBtn)
41 | }
42 |
43 | required init?(coder aDecoder: NSCoder) {
44 | fatalError("init(coder:) has not been implemented")
45 | }
46 |
47 | // MARK: - 点击事件监听
48 | @objc open func editButtonClick(editBtn: UIButton) {
49 | editBtn.isSelected = !editBtn.isSelected
50 | if self.clickClosure != nil {
51 | self.clickClosure!(editBtn.isSelected)
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ZYColumnViewDemo/ZYColumnViewDemo/ZYColumnView/ZYColumnViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZYColumnViewController.swift
3 | // 掌上遂宁
4 | //
5 | // Created by 张宇 on 2016/10/10.
6 | // Copyright © 2016年 张宇. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc protocol ZYColumnViewControllerDelegate : class {
12 | // 上面选择的数组和被选择的数组 回调传值
13 | @objc optional func columnViewControllerTitlesDidChanged(arrayTitles : [String]!, spareTitles : [String]?)
14 | // 当前用户选择的按钮标题和所处的索引
15 | @objc optional func columnViewControllerSelectedTitle(selectedTitle : String, index : Int)
16 | // 用户手动调用控制器,选择的title 和 所在索引
17 | @objc optional func columnViewControllerSetTitle(setTitle: String , index : Int)
18 | }
19 |
20 | class ZYColumnViewController: UIViewController {
21 |
22 | open var arrayTitles = [String](){
23 | didSet {
24 | // 数据校验
25 | guard arrayTitles.count > 0 else {
26 | fatalError("if you want to use it, arrayTitles can not be nil ")
27 | }
28 | for _ in view.subviews { // 已经初始化过了,直接return 避免赋值后重复执行下面的代码
29 | return
30 | }
31 | // 默认选中第0个栏目名称
32 | selTitle = arrayTitles[0]
33 | // 初始化横向滚动scrollView
34 | view.addSubview(hScrollView)
35 | // 初始化"展开"按钮
36 | setupSpreadButton()
37 | }
38 | }
39 | // 备选 string 数组
40 | open var arraySpareTitles = [String]()
41 | // 固定不变的item 个数
42 | open var fixedCount = 1
43 | // 代理
44 | weak var delegate : ZYColumnViewControllerDelegate?
45 |
46 | /************* 上面是对外属性 -----华丽分割线----- 下面是私有属性 ***************/
47 |
48 | // 右边的展开按钮
49 | fileprivate var spreadBtn: UIButton = UIButton()
50 | // 是否 展开 标识
51 | fileprivate var toSpread:Bool = false
52 | // 用户当前选中的栏目名称
53 | fileprivate var selTitle = String()
54 |
55 | // MARK: - 懒加载
56 | /// 垂直展开的scrollView
57 | fileprivate lazy var spreadView:ZYColumnSpreadView = {
58 | let spreadView = ZYColumnSpreadView(frame: CGRect(x: 0, y: 0, width: kColumnScreenW, height: 0.1))
59 | spreadView.arrayUpTitles = self.arrayTitles
60 | spreadView.arrayDownTitles = self.arraySpareTitles
61 | spreadView.backgroundColor = UIColor.init(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.9)
62 | spreadView.fixedCount = self.fixedCount
63 | self.view.insertSubview(spreadView, belowSubview: self.hScrollView)
64 |
65 | spreadView.tapClosure = {
66 | [weak self](item : ZYColumnItem) -> Void in
67 | // 回调处理
68 | // 收起spreadView
69 | self!.spreadOrFlod()
70 | if self!.selTitle != item.title { // 点击的不是当前选中的才设置,并且回传值
71 | // 这里可以拿到用户点击的具体title 如果用户已经删除之前选中的title 则认为用户选择了第0个
72 | self!.selTitle = (self!.arrayTitles.contains(item.title)) ? item.title : self!.arrayTitles[0]
73 | self!.hScrollView.changeItemToSelected(title: self!.selTitle)
74 | // 代理传值
75 | self!.delegate?.columnViewControllerSelectedTitle!(selectedTitle : self!.selTitle, index:
76 | self!.arrayTitles.index(of: self!.selTitle)!)
77 | }
78 | }
79 | spreadView.longPressClosure = {
80 | [weak self]() -> Void in
81 | // 模拟用户点击了一下edit按钮
82 | self!.upPromptView.editButtonClick(editBtn: self!.upPromptView.editBtn!)
83 | }
84 | spreadView.flodClosure = {
85 | [weak self](upArrayTitles : [String], downArrayTitles : [String]) -> Void in
86 | guard upArrayTitles != self!.arrayTitles else { // 两个数组相等,说明没有变化,下面代码不用执行
87 | return
88 | }
89 | self!.arrayTitles = upArrayTitles
90 | self!.arraySpareTitles = downArrayTitles
91 | self!.hScrollView.arrayTitles = upArrayTitles
92 | // 如果用户已经删除之前选中的title 则认为用户选择了第0个
93 | self!.selTitle = (upArrayTitles.contains(self!.selTitle)) ? self!.selTitle : self!.arrayTitles[0]
94 | self!.hScrollView.changeItemToSelected(title: self!.selTitle)
95 | // 代理传值
96 | self!.delegate?.columnViewControllerSelectedTitle!(selectedTitle: self!.selTitle, index:
97 | self!.arrayTitles.index(of: self!.selTitle)!)
98 | self!.delegate?.columnViewControllerTitlesDidChanged!(arrayTitles: self!.arrayTitles, spareTitles: self!.arraySpareTitles)
99 |
100 | }
101 | return spreadView
102 | }()
103 |
104 | /// 横向滚动的scrollView
105 | fileprivate lazy var hScrollView : ZYColumnHScrollView = {
106 | let hScrollView = ZYColumnHScrollView()
107 | // 回调
108 | hScrollView.backClosure = {
109 | [weak self](tag : Int, title: String) -> Void in
110 | if title != self!.selTitle { // 点击的不是当前选中的才设置,并且回传值
111 | self!.selTitle = title
112 | // 代理传值
113 | self!.delegate?.columnViewControllerSelectedTitle!(selectedTitle: self!.selTitle, index:
114 | self!.arrayTitles.index(of: self!.selTitle)!)
115 | }
116 | }
117 | hScrollView.arrayTitles = self.arrayTitles
118 | hScrollView.frame = CGRect(x: 0, y: 0, width: ZYScreenWidth-kColumnViewH, height: kColumnViewH)
119 | hScrollView.backgroundColor = UIColor.white
120 | hScrollView.changeItemToSelected(title: self.arrayTitles[0]) // 初始化的时候默认选中第0个
121 | self.view.addSubview(hScrollView)
122 | return hScrollView
123 | }()
124 |
125 | /// 透明的cover,当展开状态,导航条覆盖一个cover,点击cover会收起
126 | lazy fileprivate var cover : UIButton = {
127 | let btn = UIButton(frame: CGRect(x: 0, y: 0, width: kColumnScreenW , height: 64))
128 | btn.backgroundColor = UIColor(white: 1.0, alpha: 0.001)
129 | UIApplication.shared.keyWindow?.addSubview(btn)
130 | btn.addTarget(self, action: #selector(self.spreadBtnClick(spreadBtn:)), for: .touchUpInside) //等价于点了展开按钮
131 | return btn
132 | }()
133 | /// 上提示view
134 | lazy var upPromptView : ZYColumnUpPromptView = {
135 | let upView = ZYColumnUpPromptView(frame: CGRect(x: 0, y: 0, width: kColumnViewW - kColumnViewH, height: kColumnViewH))
136 | upView.backgroundColor = UIColor.white
137 | // 闭包回调处理
138 | upView.clickClosure = {
139 | [weak self](isSelected : Bool) -> Void in
140 | // 编辑按钮 点击回调事件
141 | self!.spreadView.hideDownItemsAndPromptView(toHide: isSelected)
142 | self!.spreadView.openDelStatus(showDel: isSelected)
143 | self!.spreadView.isSortStatus = isSelected
144 | self!.spreadView.scrollToTop()
145 | }
146 | self.view.insertSubview(upView, aboveSubview: self.hScrollView)
147 | return upView
148 | }()
149 |
150 | override func viewDidLoad() {
151 | super.viewDidLoad()
152 | self.automaticallyAdjustsScrollViewInsets = false
153 | view.backgroundColor = UIColor.clear
154 | }
155 | }
156 |
157 | // MARK: - 对外公共方法
158 | extension ZYColumnViewController {
159 | open func setSelectItem(title: String) {
160 | hScrollView.changeItemToSelected(title: title)
161 | delegate?.columnViewControllerSetTitle!(setTitle: title, index: arrayTitles.index(of: title)!)
162 | }
163 | }
164 |
165 | // MARK: - 初始化展开收拢按钮
166 | extension ZYColumnViewController {
167 | fileprivate func setupSpreadButton() {
168 | spreadBtn = UIButton(type: UIButtonType.custom)
169 | // 包一层UIView 作为背景
170 | let bgView = UIView(frame: CGRect(x: kColumnScreenW - kColumnViewH, y: 0.0, width: kColumnViewH, height: kColumnViewH))
171 | // 右边展开按钮(按钮为正方形,边长为控制器view的高度)
172 | spreadBtn.frame = CGRect(x: 0 , y: 0 , width: bgView.frame.width, height: bgView.frame.height)
173 | bgView.backgroundColor = UIColor.white
174 | bgView.addSubview(spreadBtn)
175 | spreadBtn.backgroundColor = UIColor.clear
176 | spreadBtn.adjustsImageWhenHighlighted = false
177 | spreadBtn.setImage(UIImage(named: "column_spread.png"), for: UIControlState.normal)
178 | spreadBtn.addTarget(self, action: #selector(self.spreadBtnClick(spreadBtn:)), for: UIControlEvents.touchUpInside) // 按钮点击事件监听
179 | view.addSubview(bgView)
180 | }
181 | }
182 |
183 | // MARK: - 控制方法
184 | extension ZYColumnViewController {
185 | // MARK: - 展开收拢控制
186 | fileprivate func spreadOrFlod() {
187 | toSpread = !toSpread
188 | // cover 和 upPromptView通过参数交给内部scrollView控制显示隐藏
189 | spreadView.doSpreadOrFold(toSpread: toSpread, cover: cover, upPromptView: upPromptView)
190 | // 与子控件scrollView同步高度,保证子控件能够响应事件
191 | self.view.frame = CGRect(x: view.frame.origin.x, y: view.frame.origin.y, width: view.frame.width, height: toSpread ? kSpreadMaxH : kColumnViewH)
192 | // 旋转按钮layer图层
193 | transitionSpreadBtn(toSpread: toSpread)
194 | // 当编辑按钮在编辑状态时,收起时要复原
195 | if !toSpread && (upPromptView.editBtn?.isSelected)! {
196 | // 模拟用户点击了一下edit按钮
197 | upPromptView.editButtonClick(editBtn: upPromptView.editBtn!)
198 | }
199 | spreadView.isSortStatus = !toSpread
200 | self.tabBarController?.tabBar.isHidden = toSpread //控制tabBar的隐藏或显示
201 | }
202 | }
203 |
204 | // MARK: - 点击事件处理
205 | extension ZYColumnViewController {
206 | /// 展开收拢按钮点击事件
207 | @objc fileprivate func spreadBtnClick(spreadBtn : UIButton) {
208 | spreadOrFlod()
209 | }
210 | /// 旋转展开按钮
211 | fileprivate func transitionSpreadBtn(toSpread : Bool) {
212 | UIView.animate(withDuration: 0.2) { () -> Void in
213 | let angle = toSpread ? .pi * 0.25 : -.pi * 0.25
214 | self.spreadBtn.transform = self.spreadBtn.transform.rotated(by: CGFloat(angle))
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------