Navigation Bar Dropdown Button? - ios

I would like a dropdown menu to drop once the user taps on the right button inside the Navigation Bar. My go to achieve this is as follow:
(1) Created a custom UIView class, which basically is going to contains the tableView to be displayed (dropped) when the user taps the Navigation Bar right button:
import UIKit
class DropdownUIView: UIView, UITableViewDelegate, UITableViewDataSource {
var dropdownTableSections = ["Ascending Order","Descending Order"]
var ascendingAndDescendingOrderSetionItmes = ["Section Designaion","Depth, h","Width, b","Area of Section, A"]
var dropdownTableView = UITableView()
override init(frame: CGRect) {
super.init(frame: frame)
dropdownTableView.delegate = self
dropdownTableView.dataSource = self
self.addSubview(dropdownTableView)
dropdownTableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
dropdownTableView.leftAnchor.constraint(equalTo: self.leftAnchor),
dropdownTableView.rightAnchor.constraint(equalTo: self.rightAnchor),
dropdownTableView.topAnchor.constraint(equalTo: self.topAnchor),
dropdownTableView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in tableView: UITableView) -> Int {
return dropdownTableSections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ascendingAndDescendingOrderSetionItmes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = ascendingAndDescendingOrderSetionItmes[indexPath.row]
return cell
}
}
(2) Created a custom UIButton Class, whereby I added to it the above dropdown view as a SubView. This is going to be the button to be added to the custom NavigationBar class as a UIView:
import UIKit
class DropdownUIButton: UIButton {
var dropdownView = DropdownUIView()
var dropdownViewHeight = NSLayoutConstraint()
var isOpen = false
override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = UIColor.darkGray
dropdownView = DropdownUIView.init(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0))
dropdownView.translatesAutoresizingMaskIntoConstraints = false
self.setTitle("Sort by:", for: .normal)
}
override func didMoveToSuperview() {
self.superview?.addSubview(dropdownView)
self.superview?.bringSubviewToFront(dropdownView)
dropdownView.topAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
dropdownView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
dropdownView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
dropdownViewHeight = dropdownView.heightAnchor.constraint(equalToConstant: 0)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if isOpen == false {
isOpen = true
NSLayoutConstraint.deactivate([self.dropdownViewHeight])
self.dropdownViewHeight.constant = 300
NSLayoutConstraint.activate([self.dropdownViewHeight])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseIn, animations: {
self.dropdownView.layoutIfNeeded()
self.dropdownView.center.y += self.dropdownView.frame.height / 2
}, completion: nil)
} else {
isOpen = false
NSLayoutConstraint.deactivate([self.dropdownViewHeight])
self.dropdownViewHeight.constant = 0
NSLayoutConstraint.activate([self.dropdownViewHeight])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseIn, animations: {
self.dropdownView.center.y -= self.dropdownView.frame.height / 2
self.dropdownView.layoutIfNeeded()
}, completion: nil)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
(3) Created a custom Navigation Bar class and added to it the custom UIButton created above as a UIView to be displayed as a rightBarButtonItem:
import UIKit
import ChameleonFramework
class CustomUINavigationBar: UINavigationBar {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
convenience init(isNavBarTranslucent: Bool, navBarBackgroundColourHexCode: String, navBarBackgroundColourAlphaValue: CGFloat, navBarStyle: UIBarStyle, preferLargeTitles: Bool, navBarDelegate: UINavigationBarDelegate, navBarItemsHexColourCode: String) {
self.init()
addNavBarRightButton()
setupNavigationBarEssentials(isNavBarTranslucent: isNavBarTranslucent, navBarBackgroundColourHexCode: navBarBackgroundColourHexCode, navBarBackgroundColourAlphaValue: navBarBackgroundColourAlphaValue, navBarStyle: navBarStyle, preferLargeTitles: preferLargeTitles, navBarDelegate: navBarDelegate, navBarItemsHexColourCode: navBarItemsHexColourCode)
}
let customNavigationBarItem = UINavigationItem()
func addNavBarRightButton() {
let button = DropdownUIButton()
let navigationBarRightButtonView: UIView = {
let view = UIView()
view.backgroundColor = .yellow
view.addSubview(button)
return view
}()
NSLayoutConstraint.activate([
button.topAnchor.constraint(equalTo: navigationBarRightButtonView.topAnchor),
button.rightAnchor.constraint(equalTo: navigationBarRightButtonView.rightAnchor),
button.leftAnchor.constraint(equalTo: navigationBarRightButtonView.leftAnchor),
button.bottomAnchor.constraint(equalTo: navigationBarRightButtonView.bottomAnchor)
])
let navigationBarRightViewitem = UIBarButtonItem(customView: navigationBarRightButtonView)
customNavigationBarItem.rightBarButtonItem = navigationBarRightViewitem
}
func setupNavigationBarEssentials(isNavBarTranslucent: Bool, navBarBackgroundColourHexCode: String, navBarBackgroundColourAlphaValue: CGFloat, navBarStyle: UIBarStyle, preferLargeTitles: Bool, navBarDelegate: UINavigationBarDelegate, navBarItemsHexColourCode: String) {
items = [customNavigationBarItem]
isTranslucent = isNavBarTranslucent
barTintColor = UIColor(hexString: navBarBackgroundColourHexCode, withAlpha: navBarBackgroundColourAlphaValue)
barStyle = navBarStyle
prefersLargeTitles = preferLargeTitles
delegate = navBarDelegate
tintColor = UIColor(hexString: navBarItemsHexColourCode)
translatesAutoresizingMaskIntoConstraints = false
}
}
(4) Added the above custom NavigationBar to the ViewController class I am interested in as below:
import UIKit
class tableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UINavigationBarDelegate {
lazy var navigationBar = CustomUINavigationBar(isNavBarTranslucent: false, navBarBackgroundColourHexCode: "#FFFFFF", navBarBackgroundColourAlphaValue: 1.0, navBarStyle: .black, preferLargeTitles: false, navBarDelegate: self, navBarItemsHexColourCode: "#FF4F40")
lazy var tableView = CustomTableView(tableViewBackgroundColourHexCode: "#0D0D0D", tableViewDelegate: self, tableViewDataSource: self, tableViewCustomCellClassToBeRegistered: IsectionsCustomTableViewCell.self, tableViewCustomCellReuseIdentifierToBeRegistered: "customCell")
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(navigationBar)
view.addSubview(tableView)
}
override func viewDidLayoutSubviews() {
setupConstraints()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! IsectionsCustomTableViewCell
cell.sectionDesignationLabel.text = "Number 1"
return cell
}
func position(for bar: UIBarPositioning) -> UIBarPosition {
return UIBarPosition.topAttached
}
func setupConstraints() {
NSLayoutConstraint.activate([
navigationBar.leftAnchor.constraint(equalTo: view.leftAnchor),
navigationBar.rightAnchor.constraint(equalTo: view.rightAnchor),
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
tableView.topAnchor.constraint(equalTo: navigationBar.bottomAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
}
}
The button gets added to the NavigationBar on its right hand side as I can see the NavigationBar and the Button. However, however, when I click on the button, nothing happens, the tableview does not get dropped down and up as I expected. Any idea where did I go wrong, and are there any CocoaPods that you can recommend to achieve something similar?

You can simply use this library to achieve drop d https://github.com/AssistoLab/DropDown

Related

swift UIViwe.animate not work in UITableViewCell

I made an animation that moves an orange View when a button is pressed.
blue = UIButton, orange = animation target View
for button in toggleButtons {
button.addTarget(self, action: #selector(toggleButtonAction), for: .touchUpInside)
}
I created 3 buttons and wrote logic to move them to the position of the buttons, but the orange view moves, but no animation is applied.
#objc func toggleButtonAction(_ sender: UIButton) {
self.toggleLeading.constant = sender.frame.width * CGFloat(sender.tag)
UIView.animate(withDuration: 3, delay: 0, options: .curveEaseIn, animations: {
self.layoutIfNeeded()
}, completion: nil)
}
The code above is my animation code. It works fine in other UIViewControllers, but it doesn't work in the Custom TableviewCell.
When the button is pressed, the orangeView moves, but it moves like a teleportation rather than an animation.
I think we need more code to see why is not working for you but I quickly tried this on a playground and seems to be working fine:
import PlaygroundSupport
import UIKit
class MyCell: UITableViewCell {
private var leadingConst: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let view = UILabel()
view.text = "Move view"
view.backgroundColor = .orange
view.translatesAutoresizingMaskIntoConstraints = false
let buttons: [UIButton] = (0...2).map {
let button = UIButton()
button.backgroundColor = .blue
button.tag = $0
button.setTitle("\($0 + 1)", for: .normal)
button.addTarget(self, action: #selector(onTap), for: .touchUpInside)
return button
}
let stackView = UIStackView(arrangedSubviews: buttons)
stackView.distribution = .fillEqually
stackView.axis = .horizontal
stackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stackView)
contentView.addSubview(view)
leadingConst = view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0)
NSLayoutConstraint.activate([
leadingConst,
view.heightAnchor.constraint(equalToConstant: 25),
view.widthAnchor.constraint(equalTo: stackView.widthAnchor, multiplier: 1 / 3),
view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
required init?(coder: NSCoder) {
nil
}
#objc func onTap(_ sender: UIButton) {
self.leadingConst.constant = sender.frame.width * CGFloat(sender.tag)
UIView.animate(withDuration: 3, delay: 0, options: .curveEaseIn, animations: {
self.contentView.layoutIfNeeded()
}, completion: nil)
}
}
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
50
}
override func numberOfSections(in tableView: UITableView) -> Int {
1
}
}
PlaygroundPage.current.liveView = ViewController()

Display array of images on a certain amount of tableview cells

I have an UIImageView inside my table view cell, named pic. I want to use an array named colors (filled with UIImages), to display on 3 tableview cells.
I have the ViewController class and the tableview cell class listed below. The tableview displays the imageview pic. I assume you would place the color array in cellForRowAt method.
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var colors:[UIImage] = [
UIImage(named: "blue")!,
UIImage(named: "red")!,
UIImage(named: "red")!
]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 118
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
class customtv: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
return view
}()
lazy var pic : UIImageview = {
let view = UIImageview(frame: CGRect(x: 100, y: 6, width: 100 , height: 100))
view.backgroundColor = .red
return view
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
addSubview(backView)
addSubview(pic)
}
}
Try with this example below
import UIKit
class ViewController1: UIViewController {
var tableView: UITableView?
var colors:[UIImage] = [
UIImage(named: "blue")!,
UIImage(named: "red")!,
UIImage(named: "red")!
]
override func viewDidLoad() {
super.viewDidLoad()
loadUI()
}
func loadUI() {
tableView = UITableView()
self.view.addSubview(tableView.unsafelyUnwrapped)
tableView?.register(CustomTVC.self, forCellReuseIdentifier: "cell")
tableView?.delegate=self
tableView?.dataSource=self
tableView?.translatesAutoresizingMaskIntoConstraints = false
tableView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView?.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView?.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
extension ViewController1: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 118
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTVC
cell.pic.image = colors[indexPath.row]
return cell
}
}
class CustomTVC: UITableViewCell {
lazy var backView : UIView = {
let view = UIView()
view.backgroundColor = .green
return view
}()
lazy var pic : UIImageView = {
let view = UIImageView()
view.backgroundColor = .red
return view
}()
override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
func commonInit() {
contentView.addSubview(backView)
backView.translatesAutoresizingMaskIntoConstraints = false
backView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4).isActive = true
backView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 4).isActive = true
backView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -4).isActive = true
backView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4).isActive = true
backView.addSubview(pic)
pic.translatesAutoresizingMaskIntoConstraints = false
pic.topAnchor.constraint(equalTo: backView.topAnchor, constant: 4).isActive = true
pic.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 4).isActive = true
pic.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -4).isActive = true
pic.widthAnchor.constraint(equalTo: pic.heightAnchor).isActive = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
}
}

How can implement two vertical button in swipe to delete in swift 5

I am trying to implement swipe to delete feature with two options, one is to delete and another one is to edit. The things I want is these options should be vertical rather than horizontal.
Thanks in advance for support.
You can easily achieve this swipe to reveal option feature using Custom TablViewCell
Design a view with two buttons and add a swipe gesture to the view to reveal the vertically aligned buttons
Anyway, I think you would rather use default method editActionsForRowAt for similar cases. If not I hope this code will help you.
class TableViewController: UIViewController {
let tableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(CustomCell.self,
forCellReuseIdentifier: CustomCell.identifier)
return tableView
}()
var selectedCell: CustomCell?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(tableView)
setupConstraints()
tableView.dataSource = self
tableView.delegate = self
tableView.reloadData()
}
func setupConstraints() {
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
}
extension TableViewController: UITableViewDelegate & UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.identifier, for: indexPath) as? CustomCell else {
return UITableViewCell()
}
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
44
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
selectedCell?.setInitialState()
}
}
extension TableViewController: CustomCellDelegate {
func didUpdateState(customCell: CustomCell?) {
if customCell != selectedCell {
selectedCell?.setInitialState()
}
selectedCell = customCell
}
}
protocol CustomCellDelegate: class {
func didUpdateState(customCell: CustomCell?)
}
class CustomCell: UITableViewCell {
weak var delegate: CustomCellDelegate?
static let identifier = "Cell"
private let customViewWidth: CGFloat = 100
private let customView: CustomView = {
let view = CustomView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .yellow
return view
}()
private let fakeContentView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
enum CustomCellState {
case hiddenCustomView
case showedCustomView
}
private var trailingConstraint = NSLayoutConstraint()
private var cellState: CustomCellState = .hiddenCustomView
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .yellow
let panGesture = UIPanGestureRecognizer(target: self, action:(#selector(handleGesture(_:))))
fakeContentView.addGestureRecognizer(panGesture)
contentView.addSubview(fakeContentView)
fakeContentView.addSubview(customView)
setConstraints()
updateCellState()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setInitialState() {
self.trailingConstraint.constant = 0
UIView.animate(withDuration: 0.5, animations: {
self.contentView.layoutIfNeeded()
})
}
#objc private func handleGesture(_ recognizer: UIPanGestureRecognizer) {
let location = recognizer.location(in: fakeContentView)
let dx = frame.width - location.x
updateFrame(deltaX: dx)
if recognizer.state == .ended {
cellState = dx > customViewWidth / 2 ? .showedCustomView : .hiddenCustomView
updateCellState()
delegate?.didUpdateState(customCell: self)
}
}
private func updateFrame(deltaX: CGFloat) {
guard abs(deltaX) <= customViewWidth else {
return
}
trailingConstraint.constant = -deltaX
contentView.layoutIfNeeded()
}
private func updateCellState() {
let dx: CGFloat = cellState == .hiddenCustomView ? 0 : customViewWidth
self.trailingConstraint.constant = -dx
UIView.animate(withDuration: 0.5, animations: {
self.contentView.layoutIfNeeded()
}, completion: nil)
}
private func setConstraints() {
trailingConstraint = fakeContentView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
trailingConstraint.isActive = true
NSLayoutConstraint.activate([
fakeContentView.topAnchor.constraint(equalTo: contentView.topAnchor),
fakeContentView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
fakeContentView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
customView.topAnchor.constraint(equalTo: fakeContentView.topAnchor),
customView.bottomAnchor.constraint(equalTo: fakeContentView.bottomAnchor),
customView.leadingAnchor.constraint(equalTo: fakeContentView.trailingAnchor),
customView.widthAnchor.constraint(equalToConstant: customViewWidth)
])
}
}
class CustomView: UIView {
private let button1: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = .blue
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private let button2: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = .black
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .gray
addSubview(button1)
addSubview(button2)
setConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setConstraints() {
NSLayoutConstraint.activate([
button1.topAnchor.constraint(equalTo: topAnchor),
button1.leadingAnchor.constraint(equalTo: leadingAnchor),
button1.trailingAnchor.constraint(equalTo: trailingAnchor),
button1.bottomAnchor.constraint(equalTo: centerYAnchor),
button2.bottomAnchor.constraint(equalTo: bottomAnchor),
button2.leadingAnchor.constraint(equalTo: leadingAnchor),
button2.trailingAnchor.constraint(equalTo: trailingAnchor),
button2.topAnchor.constraint(equalTo: button1.bottomAnchor)
])
}
}

didSelectRow event delay in swift UITableView

Image
when I am touching any cell it should be invoked but it invoked when I am holding the touch on any cell for 5 - 6 seconds. you can see in the above image.
I created the same drop-down button separately and it's working normally. but when I include it in my project then it doesn't work properly.
UIViewController
import UIKit
class Registration: UIViewController {
var genderDropDown: DropDownButton = {
let dropDown = DropDownButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
dropDown.setTitle("Gender", for: .normal)
dropDown.translatesAutoresizingMaskIntoConstraints = false
dropDown.backgroundColor = setColor(rgbValue: AppColor.pink)
dropDown.setTitleColor(.white, for: .normal)
return dropDown
}()
override func viewDidLoad() {
super.viewDidLoad()
registrationContainer.addSubview(genderDropDown)
NSLayoutConstraint.activate([
genderDropDown.topAnchor.constraint(equalTo: emailTF.bottomAnchor, constant: 30),
genderDropDown.leftAnchor.constraint(equalTo: registrationContainer.leftAnchor, constant: 20),
genderDropDown.heightAnchor.constraint(equalToConstant: 50),
genderDropDown.widthAnchor.constraint(equalToConstant: 100)
])
}
}
DropDownButton
class DropDownButton: UIButton, DropDownProtocol {
func dropDownPressed(string: String) {
self.setTitle(string, for: .normal)
self.dismissDropDown()
}
var dropDown = DropDownView()
var height = NSLayoutConstraint()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .darkGray
dropDown = DropDownView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
dropDown.delegate = self
dropDown.translatesAutoresizingMaskIntoConstraints = false
}
override func didMoveToSuperview() {
self.superview?.addSubview(dropDown)
self.superview?.bringSubviewToFront(dropDown)
dropDown.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
dropDown.topAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
dropDown.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
height = dropDown.heightAnchor.constraint(equalToConstant: 0)
}
var isOpen = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if isOpen == false{
isOpen = true
NSLayoutConstraint.deactivate([self.height])
if self.dropDown.tableView.contentSize.height > 150{
self.height.constant = 150
}
else {
self.height.constant = self.dropDown.tableView.contentSize.height
}
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropDown.layoutIfNeeded()
self.dropDown.center.y += self.dropDown.frame.height / 2
}, completion: nil)
} else {
isOpen = false
NSLayoutConstraint.deactivate([self.height])
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropDown.center.y -= self.dropDown.frame.height / 2
self.dropDown.layoutIfNeeded()
}, completion: nil)
}
}
func dismissDropDown(){
isOpen = false
NSLayoutConstraint.deactivate([self.height])
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.dropDown.center.y -= self.dropDown.frame.height / 2
self.dropDown.layoutIfNeeded()
}, completion: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
DropDownView
class DropDownView: UIView, UITableViewDelegate, UITableViewDataSource{
let items = ["Male", "Female"]
let tableView = UITableView()
var delegate: DropDownProtocol!
override init(frame: CGRect) {
super.init(frame: frame)
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(tableView)
tableView.backgroundColor = .darkGray
tableView.separatorStyle = .none
tableView.allowsSelection = true
tableView.delaysContentTouches = false
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
tableView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
DispatchQueue.main.async {
self.delegate.dropDownPressed(string: self.items[indexPath.row])
self.tableView.deselectRow(at: indexPath, animated: true)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
cell.textLabel?.text = items[indexPath.row]
cell.textLabel?.textColor = .white
cell.backgroundColor = setColor(rgbValue: AppColor.pink)
return cell
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
put your code inside DispatchQueue.
DispatchQueue.main.async {
self.delegate.dropDownPressed(string: items[indexPath.row])
self.tableView.deselectRow(at: indexPath, animated: true)
}

Can't not check button title from programmatically DropDown button

I am new in Swift and my english is not very well
The question is i build a dropdown view from this tutorial
youtube: https://youtu.be/22zu-OTS-3M
github: https://github.com/Archetapp/Drop-Down-Menu
He programmatically create a fantastic dropdown view without storyboard
the code run very good on my Xcode
but when I went to check the title with the button
I never get it.
this my code
class ViewController: UIViewController, GMSMapViewDelegate
override func viewDidLoad()
super.viewDidLoad()
let typeBTN = dropDownBtn()
self.view.addSubview(typeBTN)
typeBTN.setTitle("animal", for: .normal)
typeBTN.dropView.dropDownOptions = ["dog", "cat", "cow", "boy"]
// ....
protocol dropDownProtocol {
func dropDownPressed(string: String)
}
class dropDownBtn: UIButton, dropDownProtocol {
func dropDownPressed(string: String) {
self.setTitle(string, for: .normal)
self.dismissDropDown()
}
var dropView = dropDownView()
var height = NSLayoutConstraint()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.darkGray
dropView = dropDownView.init(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0))
dropView.delegate = self
dropView.translatesAutoresizingMaskIntoConstraints = false
}
override func didMoveToSuperview() {
self.superview?.addSubview(dropView)
self.superview?.bringSubviewToFront(dropView)
dropView.topAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
dropView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
dropView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
height = dropView.heightAnchor.constraint(equalToConstant: 0)
}
var isOpen = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if isOpen == false {
isOpen = true
NSLayoutConstraint.deactivate([self.height])
if self.dropView.tableView.contentSize.height > 150 {
self.height.constant = 170
} else {
self.height.constant = self.dropView.tableView.contentSize.height
}
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
self.dropView.layoutIfNeeded()
self.dropView.center.y += self.dropView.frame.height / 2
}, completion: nil)
}else{ dismissDropDown() }
}
func dismissDropDown() {
isOpen = false
NSLayoutConstraint.deactivate([self.height])
self.height.constant = 0
NSLayoutConstraint.activate([self.height])
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: {
self.dropView.center.y -= self.dropView.frame.height / 2
self.dropView.layoutIfNeeded()
}, completion: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class dropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
var dropDownOptions = [String]()
var tableView = UITableView()
var delegate: dropDownProtocol!
override init(frame: CGRect) {
super.init(frame: frame)
tableView.backgroundColor = UIColor.darkGray
tableView.delegate = self
tableView.dataSource = self
self.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dropDownOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = dropDownOptions[indexPath.row]
cell.backgroundColor = UIColor.darkGray
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.delegate.dropDownPressed(string: dropDownOptions[indexPath.row])
print(dropDownOptions[indexPath.row])
I have tried a lot to check when button title change. like this
print(typeBTN.currentTitle!)
print(typeBTN.titleLabel?.text! )
print(typeBTN.title(for: .normal))
//I get nothing when i pressed dropdown menu options?
because I want to do this
if typeBTN.currentTitle == "dog" {
//show some date at my mapview
}
but when I click the "dog" of dropdown menu
it never work
can somebody help me?
You can use the Delegation pattern to notify the title changes to your view controller.
Add the protocol:
protocol DropDownButtonDelegate: AnyObject {
func titleDidChange(_ newTitle: String)
}
Add in your DropDownButton class a delegate property:
weak var delegate: DropDownButtonDelegate?
Then in your dropDownPressed function:
func dropDownPressed(string: String) {
self.setTitle(string, for: .normal)
self.dismissDropDown()
delegate?.titleDidChange(string)
}
And finally in your view controller implement the DropDownButtonDelegate:
class ViewController: UIViewController, GMSMapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let typeBTN = dropDownBtn()
self.view.addSubview(typeBTN)
typeBTN.delegate = self
typeBTN.setTitle("animal", for: .normal)
typeBTN.dropView.dropDownOptions = ["dog", "cat", "cow", "boy"]
}
}
extension ViewController: DropDownButtonDelegate {
func titleDidChange(_ newTitle: String) {
print(newTitle)
}
}

Resources