From 0a866a9d453148e43fae1da9919dea224de0dfa3 Mon Sep 17 00:00:00 2001 From: ren-suke Date: Wed, 24 Mar 2021 18:23:32 +0900 Subject: [PATCH 1/3] wip --- Example/ViewController.swift | 4 +++ Sources/Classes/SwipeMenuView.swift | 10 +++++++ Sources/Classes/SwipeMenuViewController.swift | 5 +++- Sources/Classes/TabItemView.swift | 30 +++++++++++++++++-- Sources/Classes/TabView.swift | 11 +++++++ 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/Example/ViewController.swift b/Example/ViewController.swift index dfada2f..3d75710 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -70,6 +70,10 @@ final class ViewController: SwipeMenuViewController { override func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String { return children[index].title ?? "" } + + override func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationForPageAt index: Int) -> Bool { + return index % 2 == 1 ? true : false + } override func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController { let vc = children[index] diff --git a/Sources/Classes/SwipeMenuView.swift b/Sources/Classes/SwipeMenuView.swift index bfa4b19..a8caa83 100644 --- a/Sources/Classes/SwipeMenuView.swift +++ b/Sources/Classes/SwipeMenuView.swift @@ -35,6 +35,9 @@ public struct SwipeMenuViewOptions { /// ItemView selected textColor. Defaults to `.black`. public var selectedTextColor: UIColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0) + + /// ItemView notification badge color. Defaults to `.red`. + public var notificationBadgeColor: UIColor = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) } public struct AdditionView { @@ -178,6 +181,9 @@ public protocol SwipeMenuViewDataSource: class { /// Return strings to be displayed at the tab in `SwipeMenuView`. func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String + + /// Return a value to be + func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationForPageAt index: Int) -> Bool /// Return a ViewController to be displayed at the page in `SwipeMenuView`. func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController @@ -399,6 +405,10 @@ extension SwipeMenuView: TabViewDelegate, TabViewDataSource { public func tabView(_ tabView: TabView, titleForItemAt index: Int) -> String? { return dataSource?.swipeMenuView(self, titleForPageAt: index) } + + public func tabView(_ tabView: TabView, hasNotificationForItemAt index: Int) -> Bool? { + return dataSource?.swipeMenuView(self, hasNotificationForPageAt: index) + } } // MARK: - UIScrollViewDelegate diff --git a/Sources/Classes/SwipeMenuViewController.swift b/Sources/Classes/SwipeMenuViewController.swift index da6a3fc..949d097 100644 --- a/Sources/Classes/SwipeMenuViewController.swift +++ b/Sources/Classes/SwipeMenuViewController.swift @@ -1,7 +1,6 @@ import UIKit open class SwipeMenuViewController: UIViewController, SwipeMenuViewDelegate, SwipeMenuViewDataSource { - open var swipeMenuView: SwipeMenuView! open override func viewDidLoad() { @@ -61,6 +60,10 @@ open class SwipeMenuViewController: UIViewController, SwipeMenuViewDelegate, Swi open func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String { return children[index].title ?? "" } + + open func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationForPageAt index: Int) -> Bool { + return false + } open func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController { let vc = children[index] diff --git a/Sources/Classes/TabItemView.swift b/Sources/Classes/TabItemView.swift index 4b7d1ff..4a755c5 100644 --- a/Sources/Classes/TabItemView.swift +++ b/Sources/Classes/TabItemView.swift @@ -3,9 +3,12 @@ import UIKit final class TabItemView: UIView { private(set) var titleLabel: UILabel = UILabel() + private var notificationBadgeView: UIView = UIView() public var textColor: UIColor = UIColor(red: 140/255, green: 140/255, blue: 140/255, alpha: 1.0) public var selectedTextColor: UIColor = .white + public var notificationBadgeColor: UIColor = .red + public var titleLabelBoundingRect: CGRect = .zero public var isSelected: Bool = false { didSet { @@ -16,11 +19,27 @@ final class TabItemView: UIView { } } } + public var notificationBadgeViewFrame: CGRect = .zero { + didSet { + notificationBadgeView.frame = notificationBadgeViewFrame + } + } + public var hasNotification: Bool = false { + didSet { + if hasNotification { + notificationBadgeView.backgroundColor = notificationBadgeColor + notificationBadgeView.isHidden = false + } else { + notificationBadgeView.isHidden = true + } + } + } public override init(frame: CGRect) { super.init(frame: frame) setupLabel() + setupNotificationBadgeView() } required public init?(coder aDecoder: NSCoder) { @@ -40,9 +59,16 @@ final class TabItemView: UIView { addSubview(titleLabel) layoutLabel() } - + + private func setupNotificationBadgeView() { + notificationBadgeView = UIView() + notificationBadgeView.backgroundColor = .red + notificationBadgeView.layer.cornerRadius = 3 + notificationBadgeView.clipsToBounds = true + addSubview(notificationBadgeView) + } + private func layoutLabel() { - titleLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ titleLabel.topAnchor.constraint(equalTo: self.topAnchor), diff --git a/Sources/Classes/TabView.swift b/Sources/Classes/TabView.swift index 8b20a6e..45f8ad1 100644 --- a/Sources/Classes/TabView.swift +++ b/Sources/Classes/TabView.swift @@ -26,6 +26,8 @@ public protocol TabViewDataSource: class { /// Return strings to be displayed at the tab in `TabView`. func tabView(_ tabView: TabView, titleForItemAt index: Int) -> String? + + func tabView(_ tabView: TabView, hasNotificationForItemAt index: Int) -> Bool? } open class TabView: UIScrollView { @@ -220,6 +222,10 @@ open class TabView: UIScrollView { tabItemView.textColor = options.itemView.textColor tabItemView.selectedTextColor = options.itemView.selectedTextColor } + if let hasNotification = dataSource.tabView(self, hasNotificationForItemAt: index) { + tabItemView.notificationBadgeColor = options.itemView.notificationBadgeColor + tabItemView.hasNotification = hasNotification + } tabItemView.isSelected = index == currentIndex @@ -250,6 +256,11 @@ open class TabView: UIScrollView { adjustCellSize = CGSize(width: (frame.width - options.margin * 2) / CGFloat(itemCount), height: tabItemView.frame.size.height) } tabItemView.frame.size = adjustCellSize + guard let title = dataSource.tabView(self, titleForItemAt: index) else { + return + } + let textFrame = (title as NSString).boundingRect(with: tabItemView.titleLabel.frame.size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: options.itemView.font], context: nil) + tabItemView.notificationBadgeViewFrame = .init(x: textFrame.width + (adjustCellSize.width - textFrame.width) / 2 + 3, y: adjustCellSize.height / 2 - 6, width: 6, height: 6) containerView.addArrangedSubview(tabItemView) } From d1c6fd69a63afbeff5c69c66393540c6f91fa63f Mon Sep 17 00:00:00 2001 From: ren-suke Date: Wed, 24 Mar 2021 18:39:15 +0900 Subject: [PATCH 2/3] fix self-reviews --- Example/ViewController.swift | 2 +- Sources/Classes/SwipeMenuView.swift | 6 +++--- Sources/Classes/SwipeMenuViewController.swift | 2 +- Sources/Classes/TabItemView.swift | 5 +++-- Sources/Classes/TabView.swift | 6 +++++- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Example/ViewController.swift b/Example/ViewController.swift index 3d75710..13bb78f 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -71,7 +71,7 @@ final class ViewController: SwipeMenuViewController { return children[index].title ?? "" } - override func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationForPageAt index: Int) -> Bool { + override func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationPageAt index: Int) -> Bool { return index % 2 == 1 ? true : false } diff --git a/Sources/Classes/SwipeMenuView.swift b/Sources/Classes/SwipeMenuView.swift index a8caa83..cd178ca 100644 --- a/Sources/Classes/SwipeMenuView.swift +++ b/Sources/Classes/SwipeMenuView.swift @@ -182,8 +182,8 @@ public protocol SwipeMenuViewDataSource: class { /// Return strings to be displayed at the tab in `SwipeMenuView`. func swipeMenuView(_ swipeMenuView: SwipeMenuView, titleForPageAt index: Int) -> String - /// Return a value to be - func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationForPageAt index: Int) -> Bool + /// Returns whether or not the tab in `SwipeMenuView` has notifications. + func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationPageAt index: Int) -> Bool /// Return a ViewController to be displayed at the page in `SwipeMenuView`. func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController @@ -407,7 +407,7 @@ extension SwipeMenuView: TabViewDelegate, TabViewDataSource { } public func tabView(_ tabView: TabView, hasNotificationForItemAt index: Int) -> Bool? { - return dataSource?.swipeMenuView(self, hasNotificationForPageAt: index) + return dataSource?.swipeMenuView(self, hasNotificationPageAt: index) } } diff --git a/Sources/Classes/SwipeMenuViewController.swift b/Sources/Classes/SwipeMenuViewController.swift index 949d097..097a509 100644 --- a/Sources/Classes/SwipeMenuViewController.swift +++ b/Sources/Classes/SwipeMenuViewController.swift @@ -61,7 +61,7 @@ open class SwipeMenuViewController: UIViewController, SwipeMenuViewDelegate, Swi return children[index].title ?? "" } - open func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationForPageAt index: Int) -> Bool { + open func swipeMenuView(_ swipeMenuView: SwipeMenuView, hasNotificationPageAt index: Int) -> Bool { return false } diff --git a/Sources/Classes/TabItemView.swift b/Sources/Classes/TabItemView.swift index 4a755c5..403c904 100644 --- a/Sources/Classes/TabItemView.swift +++ b/Sources/Classes/TabItemView.swift @@ -4,11 +4,11 @@ final class TabItemView: UIView { private(set) var titleLabel: UILabel = UILabel() private var notificationBadgeView: UIView = UIView() + let notificationBadgeViewSize: CGSize = CGSize(width: 6, height: 6) public var textColor: UIColor = UIColor(red: 140/255, green: 140/255, blue: 140/255, alpha: 1.0) public var selectedTextColor: UIColor = .white public var notificationBadgeColor: UIColor = .red - public var titleLabelBoundingRect: CGRect = .zero public var isSelected: Bool = false { didSet { @@ -63,12 +63,13 @@ final class TabItemView: UIView { private func setupNotificationBadgeView() { notificationBadgeView = UIView() notificationBadgeView.backgroundColor = .red - notificationBadgeView.layer.cornerRadius = 3 + notificationBadgeView.layer.cornerRadius = notificationBadgeViewSize.height / 2 notificationBadgeView.clipsToBounds = true addSubview(notificationBadgeView) } private func layoutLabel() { + titleLabel.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ titleLabel.topAnchor.constraint(equalTo: self.topAnchor), diff --git a/Sources/Classes/TabView.swift b/Sources/Classes/TabView.swift index 45f8ad1..b7ec290 100644 --- a/Sources/Classes/TabView.swift +++ b/Sources/Classes/TabView.swift @@ -27,6 +27,7 @@ public protocol TabViewDataSource: class { /// Return strings to be displayed at the tab in `TabView`. func tabView(_ tabView: TabView, titleForItemAt index: Int) -> String? + /// Returns whether or not the tab in `TabView` has notifications. func tabView(_ tabView: TabView, hasNotificationForItemAt index: Int) -> Bool? } @@ -260,7 +261,10 @@ open class TabView: UIScrollView { return } let textFrame = (title as NSString).boundingRect(with: tabItemView.titleLabel.frame.size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: options.itemView.font], context: nil) - tabItemView.notificationBadgeViewFrame = .init(x: textFrame.width + (adjustCellSize.width - textFrame.width) / 2 + 3, y: adjustCellSize.height / 2 - 6, width: 6, height: 6) + tabItemView.notificationBadgeViewFrame = .init(x: textFrame.width + (adjustCellSize.width - textFrame.width) / 2 + 3, + y: adjustCellSize.height / 2 - tabItemView.notificationBadgeViewSize.height, + width: tabItemView.notificationBadgeViewSize.width, + height: tabItemView.notificationBadgeViewSize.height) containerView.addArrangedSubview(tabItemView) } From 469036e988d2e812e7e53b2379c6e64788a2c2ff Mon Sep 17 00:00:00 2001 From: ren-suke Date: Wed, 24 Mar 2021 18:47:43 +0900 Subject: [PATCH 3/3] refactor --- Sources/Classes/SwipeMenuViewController.swift | 1 + Sources/Classes/TabItemView.swift | 2 +- Sources/Classes/TabView.swift | 17 ++++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Sources/Classes/SwipeMenuViewController.swift b/Sources/Classes/SwipeMenuViewController.swift index 097a509..9a17b64 100644 --- a/Sources/Classes/SwipeMenuViewController.swift +++ b/Sources/Classes/SwipeMenuViewController.swift @@ -1,6 +1,7 @@ import UIKit open class SwipeMenuViewController: UIViewController, SwipeMenuViewDelegate, SwipeMenuViewDataSource { + open var swipeMenuView: SwipeMenuView! open override func viewDidLoad() { diff --git a/Sources/Classes/TabItemView.swift b/Sources/Classes/TabItemView.swift index 403c904..0d850f8 100644 --- a/Sources/Classes/TabItemView.swift +++ b/Sources/Classes/TabItemView.swift @@ -62,7 +62,7 @@ final class TabItemView: UIView { private func setupNotificationBadgeView() { notificationBadgeView = UIView() - notificationBadgeView.backgroundColor = .red + notificationBadgeView.isHidden = true notificationBadgeView.layer.cornerRadius = notificationBadgeViewSize.height / 2 notificationBadgeView.clipsToBounds = true addSubview(notificationBadgeView) diff --git a/Sources/Classes/TabView.swift b/Sources/Classes/TabView.swift index b7ec290..c74537a 100644 --- a/Sources/Classes/TabView.swift +++ b/Sources/Classes/TabView.swift @@ -257,14 +257,17 @@ open class TabView: UIScrollView { adjustCellSize = CGSize(width: (frame.width - options.margin * 2) / CGFloat(itemCount), height: tabItemView.frame.size.height) } tabItemView.frame.size = adjustCellSize - guard let title = dataSource.tabView(self, titleForItemAt: index) else { - return + + if let title = dataSource.tabView(self, titleForItemAt: index) { + let textFrame = (title as NSString).boundingRect(with: tabItemView.titleLabel.frame.size, + options: .usesLineFragmentOrigin, + attributes: [NSAttributedString.Key.font: options.itemView.font], + context: nil) + tabItemView.notificationBadgeViewFrame = .init(x: textFrame.width + (adjustCellSize.width - textFrame.width) / 2 + 6, + y: adjustCellSize.height / 2 - tabItemView.notificationBadgeViewSize.height, + width: tabItemView.notificationBadgeViewSize.width, + height: tabItemView.notificationBadgeViewSize.height) } - let textFrame = (title as NSString).boundingRect(with: tabItemView.titleLabel.frame.size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: options.itemView.font], context: nil) - tabItemView.notificationBadgeViewFrame = .init(x: textFrame.width + (adjustCellSize.width - textFrame.width) / 2 + 3, - y: adjustCellSize.height / 2 - tabItemView.notificationBadgeViewSize.height, - width: tabItemView.notificationBadgeViewSize.width, - height: tabItemView.notificationBadgeViewSize.height) containerView.addArrangedSubview(tabItemView) }