From 57a6c06bd847194a13a82aad199c08fbd7dba67e Mon Sep 17 00:00:00 2001 From: Beata Lin Date: Tue, 13 Aug 2019 23:57:44 +0800 Subject: [PATCH 1/3] Support cell image and title icon --- Source/BTNavigationDropdownMenu.swift | 51 ++++++++++++++++++++++++--- Source/Internal/BTConfiguration.swift | 4 +++ Source/Internal/BTTableView.swift | 6 +++- Source/Internal/BTTableViewCell.swift | 11 ++++++ 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/Source/BTNavigationDropdownMenu.swift b/Source/BTNavigationDropdownMenu.swift index 3e098428..98d9ed70 100755 --- a/Source/BTNavigationDropdownMenu.swift +++ b/Source/BTNavigationDropdownMenu.swift @@ -139,6 +139,15 @@ open class BTNavigationDropdownMenu: UIView { } } + open var iconImage: UIImage! { + get { + return self.configuration.iconImage + } + set(value) { + self.configuration.iconImage = value + } + } + // The checkmark icon of the cell open var checkMarkImage: UIImage! { get { @@ -220,6 +229,15 @@ open class BTNavigationDropdownMenu: UIView { } } + open var shouldChangeTitleImage: Bool! { + get { + return self.configuration.shouldChangeTitleImage + } + set(value) { + self.configuration.shouldChangeTitleImage = value + } + } + open var didSelectItemAtIndexHandler: ((_ indexPath: Int) -> ())? open var isShown: Bool! @@ -229,9 +247,11 @@ open class BTNavigationDropdownMenu: UIView { fileprivate var menuButton: UIButton! fileprivate var menuTitle: UILabel! fileprivate var menuArrow: UIImageView! + fileprivate var menuImage: UIImageView! fileprivate var backgroundView: UIView! fileprivate var tableView: BTTableView! fileprivate var items: [String]! + fileprivate var itemImages: [UIImage]? fileprivate var menuWrapper: UIView! required public init?(coder aDecoder: NSCoder) { @@ -248,9 +268,9 @@ open class BTNavigationDropdownMenu: UIView { - title: A string to define title to be displayed. - items: The array of items to select */ - public convenience init(navigationController: UINavigationController? = nil, containerView: UIView = UIApplication.shared.keyWindow!, title: String, items: [String]) { + public convenience init(navigationController: UINavigationController? = nil, containerView: UIView = UIApplication.shared.keyWindow!, title: String, items: [String], itemImages: [UIImage]? = nil) { - self.init(navigationController: navigationController, containerView: containerView, title: BTTitle.title(title), items: items) + self.init(navigationController: navigationController, containerView: containerView, title: BTTitle.title(title), items: items, itemImages: itemImages) } /** @@ -265,7 +285,7 @@ open class BTNavigationDropdownMenu: UIView { - title: An enum to define title to be displayed, can be a string or index of items. - items: The array of items to select */ - public init(navigationController: UINavigationController? = nil, containerView: UIView = UIApplication.shared.keyWindow!, title: BTTitle, items: [String]) { + public init(navigationController: UINavigationController? = nil, containerView: UIView = UIApplication.shared.keyWindow!, title: BTTitle, items: [String], itemImages: [UIImage]? = nil) { // Key window guard let window = UIApplication.shared.keyWindow else { super.init(frame: CGRect.zero) @@ -303,6 +323,7 @@ open class BTNavigationDropdownMenu: UIView { self.isShown = false self.items = items + self.itemImages = itemImages // Init button as navigation title self.menuButton = UIButton(frame: frame) @@ -319,6 +340,11 @@ open class BTNavigationDropdownMenu: UIView { self.menuArrow = UIImageView(image: self.configuration.arrowImage.withRenderingMode(.alwaysTemplate)) self.menuButton.addSubview(self.menuArrow) + self.menuImage = UIImageView(image: nil) + if (self.itemImages != nil) { + self.menuButton.addSubview(self.menuImage) + } + let menuWrapperBounds = window.bounds // Set up DropdownMenu @@ -341,7 +367,7 @@ open class BTNavigationDropdownMenu: UIView { // Init table view let navBarHeight = self.navigationController?.navigationBar.bounds.size.height ?? 0 let statusBarHeight = UIApplication.shared.statusBarFrame.height - self.tableView = BTTableView(frame: CGRect(x: menuWrapperBounds.origin.x, y: menuWrapperBounds.origin.y + 0.5, width: menuWrapperBounds.width, height: menuWrapperBounds.height + 300 - navBarHeight - statusBarHeight), items: items, title: titleToDisplay, configuration: self.configuration) + self.tableView = BTTableView(frame: CGRect(x: menuWrapperBounds.origin.x, y: menuWrapperBounds.origin.y + 0.5, width: menuWrapperBounds.width, height: menuWrapperBounds.height + 300 - navBarHeight - statusBarHeight), items: items, itemImages: itemImages, title: titleToDisplay, configuration: self.configuration) self.tableView.selectRowAtIndexPathHandler = { [weak self] (indexPath: Int) -> () in guard let selfie = self else { @@ -351,6 +377,9 @@ open class BTNavigationDropdownMenu: UIView { if selfie.shouldChangeTitleText! { selfie.setMenuTitle("\(selfie.tableView.items[indexPath])") } + if selfie.shouldChangeTitleImage!, let itemImages = selfie.tableView.itemImages { + selfie.setMenuImage(itemImages[indexPath]) + } self?.hideMenu() self?.layoutSubviews() } @@ -382,6 +411,8 @@ open class BTNavigationDropdownMenu: UIView { self.menuTitle.textColor = self.configuration.menuTitleColor self.menuArrow.sizeToFit() self.menuArrow.center = CGPoint(x: self.menuTitle.frame.maxX + self.configuration.arrowPadding, y: self.frame.size.height/2) + self.menuImage.sizeToFit() + self.menuImage.center = CGPoint(x: self.menuTitle.frame.minX - ((self.menuImage.image?.size.width ?? 0) / 2), y: self.frame.size.height/2) self.menuWrapper.frame.origin.y = self.navigationController!.navigationBar.frame.maxY self.tableView.reloadData() } @@ -413,6 +444,11 @@ open class BTNavigationDropdownMenu: UIView { } } + open func updateItemImages(_ images: [UIImage]?) { + self.tableView.itemImages = images + self.tableView.reloadData() + } + open func setSelected(index: Int) { self.tableView.selectedIndexPath = index self.tableView.reloadData() @@ -420,6 +456,9 @@ open class BTNavigationDropdownMenu: UIView { if self.shouldChangeTitleText! { self.setMenuTitle("\(self.tableView.items[index])") } + if self.shouldChangeTitleImage!, let itemImages = self.tableView.itemImages { + self.setMenuImage(itemImages[index]) + } } func setupDefaultConfiguration() { @@ -520,6 +559,10 @@ open class BTNavigationDropdownMenu: UIView { self.menuTitle.text = title } + func setMenuImage(_ image: UIImage) { + self.menuImage.image = image + } + @objc func menuButtonTapped(_ sender: UIButton) { self.isShown == true ? hideMenu() : showMenu() } diff --git a/Source/Internal/BTConfiguration.swift b/Source/Internal/BTConfiguration.swift index f25c5eb8..129f3433 100644 --- a/Source/Internal/BTConfiguration.swift +++ b/Source/Internal/BTConfiguration.swift @@ -34,6 +34,7 @@ final class BTConfiguration { var navigationBarTitleFont: UIFont! var cellTextLabelAlignment: NSTextAlignment! var cellSelectionColor: UIColor? + var iconImage: UIImage! var checkMarkImage: UIImage! var shouldKeepSelectedCellColor: Bool! var arrowTintColor: UIColor? @@ -43,6 +44,7 @@ final class BTConfiguration { var maskBackgroundColor: UIColor! var maskBackgroundOpacity: CGFloat! var shouldChangeTitleText: Bool! + var shouldChangeTitleImage: Bool! init() { self.defaultValue() @@ -69,6 +71,7 @@ final class BTConfiguration { self.cellTextLabelAlignment = NSTextAlignment.left self.cellSelectionColor = UIColor.lightGray self.checkMarkImage = UIImage(contentsOfFile: checkMarkImagePath!) + self.iconImage = UIImage(contentsOfFile: checkMarkImagePath!) self.shouldKeepSelectedCellColor = false self.animationDuration = 0.5 self.arrowImage = UIImage(contentsOfFile: arrowImagePath!) @@ -76,5 +79,6 @@ final class BTConfiguration { self.maskBackgroundColor = UIColor.black self.maskBackgroundOpacity = 0.3 self.shouldChangeTitleText = true + self.shouldChangeTitleImage = false } } diff --git a/Source/Internal/BTTableView.swift b/Source/Internal/BTTableView.swift index 9fb04374..88bc2fe9 100644 --- a/Source/Internal/BTTableView.swift +++ b/Source/Internal/BTTableView.swift @@ -31,16 +31,18 @@ class BTTableView: UITableView, UITableViewDelegate, UITableViewDataSource { // Private properties var items: [String] = [] + var itemImages: [UIImage]? = nil var selectedIndexPath: Int? required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - init(frame: CGRect, items: [String], title: String, configuration: BTConfiguration) { + init(frame: CGRect, items: [String], itemImages: [UIImage]? = nil, title: String, configuration: BTConfiguration) { super.init(frame: frame, style: UITableView.Style.plain) self.items = items + self.itemImages = itemImages self.selectedIndexPath = items.index(of: title) self.configuration = configuration @@ -78,6 +80,8 @@ class BTTableView: UITableView, UITableViewDelegate, UITableViewDataSource { let cell = BTTableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "Cell", configuration: self.configuration) cell.textLabel?.text = self.items[(indexPath as NSIndexPath).row] cell.checkmarkIcon.isHidden = ((indexPath as NSIndexPath).row == selectedIndexPath) ? false : true + cell.icon.image = self.itemImages?[indexPath.row] + return cell } diff --git a/Source/Internal/BTTableViewCell.swift b/Source/Internal/BTTableViewCell.swift index 9648b9c8..da0e4d50 100644 --- a/Source/Internal/BTTableViewCell.swift +++ b/Source/Internal/BTTableViewCell.swift @@ -27,6 +27,7 @@ class BTTableViewCell: UITableViewCell { let checkmarkIconWidth: CGFloat = 50 let horizontalMargin: CGFloat = 20 + var icon: UIImageView! var checkmarkIcon: UIImageView! var cellContentFrame: CGRect! var configuration: BTConfiguration! @@ -64,6 +65,16 @@ class BTTableViewCell: UITableViewCell { self.checkmarkIcon.contentMode = UIView.ContentMode.scaleAspectFill self.contentView.addSubview(self.checkmarkIcon) + self.icon = UIImageView(frame: CGRect(x: horizontalMargin - 15, y: (cellContentFrame.height - 30)/2, width: 30, height: 30)) + self.icon.contentMode = UIView.ContentMode.scaleAspectFill + self.contentView.addSubview(self.icon) + if let image = self.configuration.iconImage { + self.icon.image = image + if self.textLabel!.textAlignment == .left { + self.textLabel!.frame = CGRect(x: self.icon.frame.maxX, y: 0, width: cellContentFrame.width, height: cellContentFrame.height) + } + } + // Separator for cell let separator = BTTableCellContentView(frame: cellContentFrame) if let cellSeparatorColor = self.configuration.cellSeparatorColor { From a72b3ae1969ddfa760b8a731eda5c1d34daf69bb Mon Sep 17 00:00:00 2001 From: Beata Lin Date: Tue, 13 Aug 2019 23:58:16 +0800 Subject: [PATCH 2/3] Keep selected cell color (foreground) --- Source/Internal/BTTableView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Internal/BTTableView.swift b/Source/Internal/BTTableView.swift index 88bc2fe9..f21a00c4 100644 --- a/Source/Internal/BTTableView.swift +++ b/Source/Internal/BTTableView.swift @@ -106,6 +106,7 @@ class BTTableView: UITableView, UITableViewDelegate, UITableViewDataSource { if self.configuration.shouldKeepSelectedCellColor == true { cell.backgroundColor = self.configuration.cellBackgroundColor cell.contentView.backgroundColor = ((indexPath as NSIndexPath).row == selectedIndexPath) ? self.configuration.cellSelectionColor : self.configuration.cellBackgroundColor + cell.textLabel?.textColor = ((indexPath as NSIndexPath).row == selectedIndexPath) ? self.configuration.selectedCellTextLabelColor : self.configuration.cellTextLabelColor } } } From 2fdcbd30141332ba7de650da260b71d1a1cc7d86 Mon Sep 17 00:00:00 2001 From: Beata Lin Date: Tue, 13 Aug 2019 23:59:23 +0800 Subject: [PATCH 3/3] Re-calculate touch area in layoutSubview --- Source/BTNavigationDropdownMenu.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/BTNavigationDropdownMenu.swift b/Source/BTNavigationDropdownMenu.swift index 98d9ed70..a8b0f3f4 100755 --- a/Source/BTNavigationDropdownMenu.swift +++ b/Source/BTNavigationDropdownMenu.swift @@ -406,6 +406,13 @@ open class BTNavigationDropdownMenu: UIView { } override open func layoutSubviews() { + let titleToDisplay = self.menuTitle.text ?? "" + let titleSize = (titleToDisplay as NSString).size(withAttributes: [NSAttributedString.Key.font:self.configuration.navigationBarTitleFont]) + let frame = CGRect(x: 0, y: 0, width: titleSize.width + (self.configuration.arrowPadding + self.configuration.arrowImage.size.width)*2, height: self.navigationController!.navigationBar.frame.height) + + + self.frame = frame + self.menuTitle.sizeToFit() self.menuTitle.center = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2) self.menuTitle.textColor = self.configuration.menuTitleColor @@ -413,6 +420,7 @@ open class BTNavigationDropdownMenu: UIView { self.menuArrow.center = CGPoint(x: self.menuTitle.frame.maxX + self.configuration.arrowPadding, y: self.frame.size.height/2) self.menuImage.sizeToFit() self.menuImage.center = CGPoint(x: self.menuTitle.frame.minX - ((self.menuImage.image?.size.width ?? 0) / 2), y: self.frame.size.height/2) + self.menuButton.frame = frame self.menuWrapper.frame.origin.y = self.navigationController!.navigationBar.frame.maxY self.tableView.reloadData() } @@ -446,7 +454,6 @@ open class BTNavigationDropdownMenu: UIView { open func updateItemImages(_ images: [UIImage]?) { self.tableView.itemImages = images - self.tableView.reloadData() } open func setSelected(index: Int) { @@ -554,11 +561,11 @@ open class BTNavigationDropdownMenu: UIView { } }) } - + func setMenuTitle(_ title: String) { self.menuTitle.text = title } - + func setMenuImage(_ image: UIImage) { self.menuImage.image = image }