diff --git a/README.md b/README.md
index aca691b..7a8f75b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,4 @@
-
-
-
+# SwipeMenuViewController
[](https://developer.apple.com/iphone/index.action)
@@ -11,7 +9,6 @@
[](http://mit-license.org)
-
## Overview
SwipeMenuViewController provides `SwipeMenuView` and `SwipeMenuViewController`.
This is very useful to build swipe-based paging UI.
@@ -255,6 +252,12 @@ func jump(to index: Int, animated: Bool)
func willChangeOrientation()
```
+`TabView` has the following methods.
+```swift
+
+/// Reloads all `TabView` item views with the dataSource and refreshes the display.
+public func reloadData(options: SwipeMenuViewOptions.TabView? = nil, default defaultIndex: Int? = nil)
+```
### Protocols
`SwipeMenuViewDataSource` and `SwipeMenuViewDelegate` has the following methods.
@@ -296,6 +299,16 @@ open weak var dataSource: SwipeMenuDataSource!
private(set) var currentIndex
```
+`TabView` has the following properties.
+```swift
+
+// An object conforms `TabViewDelegate`. Provide views to populate the `TabView`.
+open weak var tabViewDelegate: TabViewDelegate?
+
+// An object conforms `TabViewDataSource`. Provide views and respond to `TabView` events.
+open weak var dataSource: TabViewDataSource?
+```
+
### Customization
`SwipeMenuView` is customizable by designated options property when calling `reloadData()` method.
Here are many properties of `SwipeMenuViewOptions` which you are able to customize it for your needs.
diff --git a/Sources/SwipeMenuView.swift b/Sources/SwipeMenuView.swift
index 49a8ffa..39e42a8 100644
--- a/Sources/SwipeMenuView.swift
+++ b/Sources/SwipeMenuView.swift
@@ -83,6 +83,8 @@ public struct SwipeMenuViewOptions {
/// UnderlineView options
public var underlineView = UndelineView()
+
+ public init() { }
}
public struct ContentScrollView {
@@ -148,10 +150,10 @@ public protocol SwipeMenuViewDataSource: class {
/// Return the number of pages in `SwipeMenuView`.
func numberOfPages(in swipeMenuView: SwipeMenuView) -> Int
- /// Return strings to be displayed at the specified tag in `SwipeMenuView`.
+ /// Return strings to be displayed at the tab in `SwipeMenuView`.
func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String
- /// Return a ViewController to be displayed at the specified page in `SwipeMenuView`.
+ /// Return a ViewController to be displayed at the page in `SwipeMenuView`.
func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController
}
@@ -169,6 +171,7 @@ open class SwipeMenuView: UIView {
didSet {
guard let tabView = tabView else { return }
tabView.dataSource = self
+ tabView.tabViewDelegate = self
addSubview(tabView)
layout(tabView: tabView)
}
@@ -294,7 +297,6 @@ open class SwipeMenuView: UIView {
tabView = TabView(frame: CGRect(x: 0, y: 0, width: frame.width, height: options.tabView.height), options: options.tabView)
tabView?.clipsToBounds = options.tabView.clipsToBounds
- addTabItemGestures()
contentScrollView = ContentScrollView(frame: CGRect(x: 0, y: options.tabView.height, width: frame.width, height: frame.height - options.tabView.height), default: defaultIndex, options: options.contentScrollView)
contentScrollView?.clipsToBounds = options.contentScrollView.clipsToBounds
@@ -345,58 +347,29 @@ open class SwipeMenuView: UIView {
}
}
-// MARK: - TabViewDataSource
-
-extension SwipeMenuView: TabViewDataSource {
-
- public func numberOfItems(in menuView: TabView) -> Int {
- return dataSource?.numberOfPages(in: self) ?? 0
- }
-
- public func tabView(_ tabView: TabView, titleForItemAt index: Int) -> String? {
- return dataSource?.swipeMenuView(self, titleForPageAt: index)
- }
-}
+// MARK: - TabViewDelegate, TabViewDataSource
-// MARK: - GestureRecognizer
+extension SwipeMenuView: TabViewDelegate, TabViewDataSource {
-extension SwipeMenuView {
+ public func tabView(_ tabView: TabView, didSelectTabAt index: Int) {
- fileprivate var tapGestureRecognizer: UITapGestureRecognizer {
- let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapItemView(_:)))
- gestureRecognizer.numberOfTapsRequired = 1
- gestureRecognizer.cancelsTouchesInView = false
- return gestureRecognizer
- }
-
- fileprivate func addTabItemGestures() {
- tabView?.itemViews.forEach {
- $0.addGestureRecognizer(tapGestureRecognizer)
- }
- }
-
- @objc func tapItemView(_ recognizer: UITapGestureRecognizer) {
-
- guard let itemView = recognizer.view as? TabItemView, let tabView = tabView, let index: Int = tabView.itemViews.index(of: itemView), let contentScrollView = contentScrollView else { return }
- if currentIndex == index { return }
+ guard let contentScrollView = contentScrollView,
+ currentIndex != index else { return }
isJumping = true
jumpingToIndex = index
contentScrollView.jump(to: index, animated: true)
- moveTabItem(tabView: tabView, index: index)
update(from: currentIndex, to: index)
}
- private func moveTabItem(tabView: TabView, index: Int) {
+ public func numberOfItems(in menuView: TabView) -> Int {
+ return dataSource?.numberOfPages(in: self) ?? 0
+ }
- switch options.tabView.addition {
- case .underline:
- tabView.animateUnderlineView(index: index, completion: nil)
- case .none:
- tabView.update(index)
- }
+ public func tabView(_ tabView: TabView, titleForItemAt index: Int) -> String? {
+ return dataSource?.swipeMenuView(self, titleForPageAt: index)
}
}
diff --git a/Sources/TabView.swift b/Sources/TabView.swift
index be993dc..1ad2f4d 100644
--- a/Sources/TabView.swift
+++ b/Sources/TabView.swift
@@ -1,15 +1,37 @@
import UIKit
-public protocol TabViewDataSource {
+// MARK: - TabViewDelegate
+public protocol TabViewDelegate: class {
+
+ /// Called before selecting the tab.
+ func tabView(_ tabView: TabView, willSelectTabAt index: Int)
+
+ /// Called after selecting the tab.
+ func tabView(_ tabView: TabView, didSelectTabAt index: Int)
+}
+
+extension TabViewDelegate {
+ public func tabView(_ tabView: TabView, willSelectTabAt index: Int) {}
+
+ public func tabView(_ tabView: TabView, didSelectTabAt index: Int) {}
+}
+
+// MARK: - TabViewDataSource
+
+public protocol TabViewDataSource: class {
+
+ /// Return the number of Items in `TabView`.
func numberOfItems(in tabView: TabView) -> Int
+ /// Return strings to be displayed at the tab in `TabView`.
func tabView(_ tabView: TabView, titleForItemAt index: Int) -> String?
}
open class TabView: UIScrollView {
- open var dataSource: TabViewDataSource!
+ open weak var tabViewDelegate: TabViewDelegate?
+ open weak var dataSource: TabViewDataSource?
var itemViews: [TabItemView] = []
@@ -19,7 +41,7 @@ open class TabView: UIScrollView {
fileprivate var currentIndex: Int = 0
- fileprivate var options: SwipeMenuViewOptions.TabView = SwipeMenuViewOptions.TabView()
+ fileprivate(set) var options: SwipeMenuViewOptions.TabView = SwipeMenuViewOptions.TabView()
private var leftMarginConstraint: NSLayoutConstraint = .init()
private var widthConstraint: NSLayoutConstraint = .init()
@@ -37,7 +59,7 @@ open class TabView: UIScrollView {
}
open override func didMoveToSuperview() {
- setup()
+ reloadData()
}
open override func layoutSubviews() {
@@ -57,22 +79,6 @@ open class TabView: UIScrollView {
layoutIfNeeded()
}
- public func reset() {
-
- itemViews.forEach { $0.removeFromSuperview() }
- underlineView.removeFromSuperview()
- containerView.removeFromSuperview()
- itemViews = []
- }
-
- public func update(_ index: Int) {
-
- if currentIndex == index { return }
-
- currentIndex = index
- updateSelectedItem(by: currentIndex)
- }
-
fileprivate func focus(on target: UIView, animated: Bool = true) {
if options.style == .segmented { return }
@@ -99,16 +105,43 @@ open class TabView: UIScrollView {
// MARK: - Setup
- fileprivate func setup() {
+ /// Reloads all `TabView` item views with the dataSource and refreshes the display.
+ public func reloadData(options: SwipeMenuViewOptions.TabView? = nil,
+ default defaultIndex: Int? = nil) {
+
+ if let options = options {
+ self.options = options
+ }
reset()
- guard dataSource.numberOfItems(in: self) > 0 else { return }
+ guard let dataSource = dataSource,
+ dataSource.numberOfItems(in: self) > 0 else { return }
setupScrollView()
- setupContainerView()
- setupTabItemViews()
+ setupContainerView(dataSource: dataSource)
+ setupTabItemViews(dataSource: dataSource)
setupUnderlineView()
+
+ if let defaultIndex = defaultIndex {
+ updateSelectedItem(by: defaultIndex)
+ }
+ }
+
+ func reset() {
+
+ itemViews.forEach { $0.removeFromSuperview() }
+ underlineView.removeFromSuperview()
+ containerView.removeFromSuperview()
+ itemViews = []
+ }
+
+ func update(_ index: Int) {
+
+ if currentIndex == index { return }
+
+ currentIndex = index
+ updateSelectedItem(by: currentIndex)
}
fileprivate func setupScrollView() {
@@ -123,7 +156,7 @@ open class TabView: UIScrollView {
translatesAutoresizingMaskIntoConstraints = false
}
- fileprivate func setupContainerView() {
+ fileprivate func setupContainerView(dataSource: TabViewDataSource) {
containerView.alignment = .leading
@@ -168,7 +201,7 @@ open class TabView: UIScrollView {
addSubview(containerView)
}
- fileprivate func setupTabItemViews() {
+ fileprivate func setupTabItemViews(dataSource: TabViewDataSource) {
itemViews = []
@@ -232,6 +265,7 @@ open class TabView: UIScrollView {
}
layout(containerView: containerView, containerWidth: xPosition)
+ addTabItemGestures()
animateUnderlineView(index: currentIndex)
}
@@ -320,7 +354,9 @@ extension TabView {
}
fileprivate func resetUnderlineViewPosition(index: Int) {
- guard options.style == .segmented, dataSource.numberOfItems(in: self) > 0 else { return }
+ guard options.style == .segmented,
+ let dataSource = dataSource,
+ dataSource.numberOfItems(in: self) > 0 else { return }
let adjustCellWidth: CGFloat
if #available(iOS 11.0, *), options.isSafeAreaEnabled && safeAreaInsets != .zero {
adjustCellWidth = (frame.width - options.margin * 2 - safeAreaInsets.left - safeAreaInsets.right) / CGFloat(dataSource.numberOfItems(in: self)) - options.underlineView.margin * 2
@@ -413,3 +449,42 @@ extension TabView {
focus(on: currentItem, animated: false)
}
}
+
+// MARK: - GestureRecognizer
+
+extension TabView {
+
+ fileprivate var tapGestureRecognizer: UITapGestureRecognizer {
+ let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapItemView(_:)))
+ gestureRecognizer.numberOfTapsRequired = 1
+ gestureRecognizer.cancelsTouchesInView = false
+ return gestureRecognizer
+ }
+
+ fileprivate func addTabItemGestures() {
+ itemViews.forEach {
+ $0.addGestureRecognizer(tapGestureRecognizer)
+ }
+ }
+
+ @objc func tapItemView(_ recognizer: UITapGestureRecognizer) {
+ guard let itemView = recognizer.view as? TabItemView,
+ let index: Int = itemViews.index(of: itemView),
+ currentIndex != index else { return }
+ tabViewDelegate?.tabView(self, willSelectTabAt: index)
+ moveTabItem(index: index)
+ update(index)
+ tabViewDelegate?.tabView(self, didSelectTabAt: index)
+ }
+
+ private func moveTabItem(index: Int) {
+
+ switch options.addition {
+ case .underline:
+ animateUnderlineView(index: index, completion: nil)
+ case .none:
+ update(index)
+ }
+ }
+}
+