Blame view

HDFwear/Basic/View/LTScrollView/LTPageView/LTPageView.swift 9.18 KB
f2cf74c7   yangbin   1.0.20(4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  //
  //  LTPageView.swift
  //  LTScrollView
  //
  //  Created by 高刘通 on 2017/11/14.
  //  Copyright © 2017 LT. All rights reserved.
  //
  
  import UIKit
  
  public typealias PageViewDidSelectIndexBlock = (LTPageView, Int) -> Void
  public typealias AddChildViewControllerBlock = (Int, UIViewController) -> Void
  
  @objc public protocol LTPageViewDelegate: class {
      @objc optional func glt_scrollViewDidScroll(_ scrollView: UIScrollView)
      @objc optional func glt_scrollViewWillBeginDragging(_ scrollView: UIScrollView)
      @objc optional func glt_scrollViewWillBeginDecelerating(_ scrollView: UIScrollView)
      @objc optional func glt_scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
      @objc optional func glt_scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool)
      @objc optional func glt_scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView)
  }
  
  //MARK: LTPageView相关的接口见此处
  @objc protocol LTPageViewHeaders {
      
      //MARK: 构造方法
      @objc init(frame: CGRect, currentViewController: UIViewController, viewControllers:[UIViewController], titles: [String], layout: LTLayout)
      
      //MARK: 选中了第几个位置
      @objc var didSelectIndexBlock: PageViewDidSelectIndexBlock? { get }
      
      //MARK: 添加完子控制器回调
      @objc var addChildVcBlock: AddChildViewControllerBlock? { get }
      
      //MARK: 点击切换滚动过程动画
      @objc var isClickScrollAnimation: Bool { get }
      
      //MARK: pageView代理
      @objc weak var delegate: LTPageViewDelegate? { get }
      
      //MARK: 自定义子view
      @objc func customLayoutItems(handle: (([LTPageTitleItemView], LTPageView) -> Void)?)
  }
  
  public class LTPageView: UIView, LTPageViewHeaders {
      
      //当前的控制器
      private weak var currentViewController: UIViewController?
      
      //控制器数组
      private var viewControllers: [UIViewController]
      
      //标题数组
      private var titles: [String]
      
      //设置默认布局具体设置请查看LTLayout类
      private var layout: LTLayout
      
      //当前选中的位置
      private var glt_currentIndex: Int = 0;
      
      //选中了第几个位置
      @objc public var didSelectIndexBlock: PageViewDidSelectIndexBlock?
      
      //添加完子控制器回调
      @objc public var addChildVcBlock: AddChildViewControllerBlock?
      
      // 点击切换滚动过程动画
      @objc public var isClickScrollAnimation = false {
          didSet {
              titleView.isClickScrollAnimation = isClickScrollAnimation
          }
      }
      
      //pageView的scrollView左右滑动监听
      @objc public weak var delegate: LTPageViewDelegate?
      
      //自定义子view
      func customLayoutItems(handle: (([LTPageTitleItemView], LTPageView) -> Void)?) {
          handle?(titleView.allItemViews(), self)
      }
      
      private lazy var titleView: LTPageTitleView = {
          let titleView = LTPageTitleView(frame: CGRect(x: 0, y: 0, width: glt_width, height: layout.sliderHeight), titles: titles, layout: layout)
          titleView.backgroundColor = layout.titleViewBgColor
          return titleView
      }()
      
      private lazy var scrollView: UIScrollView = {
          let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: glt_width, height: glt_height))
          scrollView.contentSize = CGSize(width: glt_width * CGFloat(self.titles.count), height: 0)
          scrollView.isPagingEnabled = true
          scrollView.delegate = self
          scrollView.bounces = layout.isShowBounces
          scrollView.isScrollEnabled = layout.isScrollEnabled
          scrollView.showsHorizontalScrollIndicator = layout.showsHorizontalScrollIndicator
          if #available(iOS 11.0, *) {
              scrollView.contentInsetAdjustmentBehavior = .never
          }
          return scrollView
      }()
      
      @objc required public init(frame: CGRect, currentViewController: UIViewController, viewControllers:[UIViewController], titles: [String], layout: LTLayout) {
          self.currentViewController = currentViewController
          self.viewControllers = viewControllers
          self.titles = titles
          self.layout = layout
          guard viewControllers.count == titles.count else {
              fatalError("控制器数量和标题数量不一致")
          }
          super.init(frame: frame)
          
          self.addSubview(self.scrollView)
          
          guard !layout.isSinglePageView else { return }
          
          addSubview(self.titleView)
          
          glt_createViewController(0)
          
          _makeupPageView(self.titleView)
      }
      
      /* 滚动到某个位置 */
      @objc public func scrollToIndex(index: Int)  {
          titleView.mainScrollView = scrollView
          titleView.scrollToIndex(index: index)
      }
      
      required public init?(coder aDecoder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }
  }
  
  extension LTPageView {
      
      final func _makeupPageView(_ titleView: LTPageTitleView) {
          
          //设置滑动view的代理为LTPageTitleView
          self.delegate = titleView
          
          //将当前的scrollView传递给titleView
          titleView.mainScrollView = scrollView
          
          //当titleView的选中位置传递给scrollView
          titleView.scrollIndexHandle = {[weak self] in
              guard let `self` = self else { return 0 }
              return self.currentIndex()
          }
          
          //通过pageView创建自子控制器
          titleView.glt_createViewControllerHandle = {[weak self] index in
              self?.glt_createViewController(index)
          }
          
          //选中某个位置的回调
          titleView.glt_didSelectTitleViewHandle = {[weak self] index in
              guard let `self` = self else { return }
              self.didSelectIndexBlock?(self, index)
          }
      }
      
      final func makeupPageView(_ pageView:LTPageView, _ titleView: LTPageTitleView) {
          //设置滑动view的代理为LTPageTitleView
          pageView.delegate = titleView
          titleView.mainScrollView = pageView.scrollView
          titleView.scrollIndexHandle = {[weak pageView] in
              return pageView?.currentIndex() ?? 0
          }
          titleView.glt_createViewControllerHandle = {[weak pageView] index in
              pageView?.glt_createViewController(index)
          }
          titleView.glt_didSelectTitleViewHandle = {[weak pageView] index in
              pageView?.didSelectIndexBlock?((pageView)!, index)
          }
      }
  }
  
  extension LTPageView {
      
      //仅内部调用创建控制器
      final func glt_createViewController(_ index: Int)  {
          
          //如果当前控制器不存在直接return
          guard let currentViewController = currentViewController else { return }
          
          let viewController = viewControllers[index]
          
          //判断是否包含当前控制器如果包含无需要再次创建
          guard !currentViewController.children.contains(viewController) else { return }
          
          //设置viewController的frame
          let X = scrollView.glt_width * CGFloat(index)
          let Y = layout.isSinglePageView ? 0 : layout.sliderHeight
          let W = scrollView.glt_width
          let H = scrollView.glt_height
          viewController.view.frame = CGRect(x: X, y: Y, width: W, height: H)
          
          //将控制器的view添加到scrollView上
          scrollView.addSubview(viewController.view)
          
          //将控制器作为当前控制器的子控制器
          currentViewController.addChild(viewController)
                  
          //抛出回调给外界
          addChildVcBlock?(index, viewController)
          
          guard let glt_scrollView = viewController.glt_scrollView else { return }
          
          if #available(iOS 11.0, *) {
              glt_scrollView.contentInsetAdjustmentBehavior = .never
          }else {
              viewController.automaticallyAdjustsScrollViewInsets = false
          }
          //修正外部scrollView的高
          glt_scrollView.glt_height = glt_scrollView.glt_height - Y
      }
      
      //获取当前位置
      private func currentIndex() -> Int {
          if scrollView.bounds.width == 0 || scrollView.bounds.height == 0 {
              return 0
          }
          let index = Int((scrollView.contentOffset.x + scrollView.bounds.width * 0.5) / scrollView.bounds.width)
          return max(0, index)
      }
  }
  
  //MARK: 提供给外界监听的方法
  extension LTPageView: UIScrollViewDelegate {
      
      public func scrollViewDidScroll(_ scrollView: UIScrollView) {
          delegate?.glt_scrollViewDidScroll?(scrollView)
      }
      
      public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
          delegate?.glt_scrollViewWillBeginDragging?(scrollView)
      }
      
      public func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
          delegate?.glt_scrollViewWillBeginDecelerating?(scrollView)
      }
      
      public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
          delegate?.glt_scrollViewDidEndDecelerating?(scrollView)
      }
      
      public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
          delegate?.glt_scrollViewDidEndDragging?(scrollView, willDecelerate: decelerate)
      }
      
      public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
          delegate?.glt_scrollViewDidEndScrollingAnimation?(scrollView)
      }
  }