I didn't find in the documentation how to add ability to select multiple rows (see the attached screenshot). I know how to do it with ordinary UITableView, but when I use Eureka and call tableView.setEditing(true, animated: true) nothing happens. Is there any way to implement this with Eureka?
Use a MultipleSelectorRow, for example:
<<< MultipleSelectorRow<Emoji>() {
$0.title = "MultipleSelectorRow"
$0.options = [💁🏻, 🍐, 👦🏼, 🐗, 🐼, 🐻]
$0.value = []
}
.onPresent { from, to in
to.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: from, action: #selector(YourViewController.multipleSelectorDone(_:)))
}
Use it to present a to view controller with multiple choices.
Related
I'm new to Swift.
I would like to know if possible add a "favorite" Button programmatically inside a view controller that inherits from UITableView?
I need to say too that I wanna use this button to favorite a result from google API.
This is possible once the result comes from a search's result and not from a specific list?
PS: I'm doing my project in UIKIT.
Thank you.
Of course your view controller will then inherit from UITableViewController, not UITableView.
Here are the basics:
var favoriteButtonItem: UIBarButtonItem?
var isFavorite: Bool = <...initial value...>
var favoriteImage
{
return UIImage(systemName: "heart" + (isFavorite ? ".fill" : ""))
}
favoriteButtonItem = UIBarButtonItem(image: favoriteImage,
style: .plain,
target: self,
action: #selector(toggleFavorite))
navigationItem.rightBarButtonItem = favoriteButtonItem
#objc private func toggleFavorite()
{
isFavorite = !isFavorite
favoriteButtonItem.image = favoriteImage
<...logic to process change...>
}
You'll need to add logic to disable or not show yet favoriteButtonItem until the backend has returned the current value.
I'm having difficulty trying to add a UIBarButtonItem with title "Next(#)" where # is a dynamic counter that counts the number of cells selected in the table view as the user is selecting them. The array that tracks the cell selections is built and working properly however the count isn't getting updated; print lines in the console work as expected. My intent later is to only show the "(#)" when the count is greater than zero but right now I'm focused on just getting the count to update after each cell gets selected/deselected.
override func viewWillAppear(_ animated: Bool) {
let barButtonCounter = "(\(invitedContacts.count))"
let barButtonItemText = "Next\(barButtonCounter)"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "\(barButtonItemText)", style: .done, target: self, action: nil)
}
This is the closest SO thread I could find but from what I can tell it's not exactly doing what I want, at least visual design-wise but maybe totally and is written in Obj-C which I don't fully comprehend as I'm new to swift. My preference would be to build this natively without importing a library.
try with this lines
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//your code for your counter
self.navigationItem.rightBarButtonItem = nil
let barButtonCounter = "(\(invitedContacts.count))"
let barButtonItemText = "Next\(barButtonCounter)"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "\(barButtonItemText)", style: .done, target: self, action: nil)
}
You are only calling it once in viewWillAppear, i recommend you create a private function that takes as parameter the new count and updates the button, and you call that in every didSelect and didDeselect delegate methods from the tableView
I want to hide/show a UIBarButtonItem when a segmentedControl changes, this is my code:
#objc fileprivate func handleSegmentedChange() {
switch segmentedControl.selectedSegmentIndex {
case index0:
// Set the proper rightBarButtonItems, in the first load this bar button items will be nil, this is why we have to check first
self.navigationItem.rightBarButtonItems?.append(UIBarButtonItem(image: #imageLiteral(resourceName: "Filter2"), style: .plain, target: self, action: #selector(openBottomSheet)))
default:
self.navigationItem.rightBarButtonItems?.remove(at: 0)
}
}
However is not updating the views (hiding or showing anything).
Note I've also tried setting the rightBarButtonItems to nil before adding or removing items, however is not working.
How can I accomplish the desired effect?
If rightBarButtonItems is nil before you try to append or remove items to/from it, then nothing will happen as you cannot append or remove items to/from a non-existent array.
Instead of appending/removing to/from rightBarButtonItems, try just setting it directly to the items you want it to be, like this:
#objc fileprivate func handleSegmentedChange() {
switch segmentedControl.selectedSegmentIndex {
case 0:
let barButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "Filter2"),
style: .plain,
target: self,
action: #selector(openBottomSheet))
navigationItem.rightBarButtonItems = [barButtonItem]
// Note: If you're just dealing with one bar button item,
// you could also just use `navigationItem.rightBarButtonItem` like:
// navigationItem.rightBarButtonItem = barButtonItem
default:
navigationItem.rightBarButtonItems = nil // or `= []`
// Note: If you're just dealing with one bar button item,
// you could also just use `navigationItem.rightBarButtonItem` like:
// navigationItem.rightBarButtonItem = nil
}
}
I've been trying to implement this toolbar, where only the 'Next' button is enabled when the top textField is the firstResponder and only the 'Previous' button is enabled when the bottom textField is the firstResponder.
It kind of works, but i need to execute my own code by accessing previous, next and done buttons action methods in other classes(like delegates)
Thanks in advance for your suggestions..
extension UIViewController {
func addInputAccessoryForTextFields(textFields: [UITextField], dismissable: Bool = true, previousNextable: Bool = false) {
for (index, textField) in textFields.enumerated() {
let toolbar: UIToolbar = UIToolbar()
toolbar.sizeToFit()
var items = [UIBarButtonItem]()
if previousNextable {
let previousButton = UIBarButtonItem(image: UIImage(named: "Backward Arrow"), style: .plain, target: nil, action: nil)
previousButton.width = 30
if textField == textFields.first {
previousButton.isEnabled = false
} else {
previousButton.target = textFields[index - 1]
previousButton.action = #selector(UITextField.becomeFirstResponder)
}
let nextButton = UIBarButtonItem(image: UIImage(named: "Forward Arrow"), style: .plain, target: nil, action: nil)
nextButton.width = 30
if textField == textFields.last {
nextButton.isEnabled = false
} else {
nextButton.target = textFields[index + 1]
nextButton.action = #selector(UITextField.becomeFirstResponder)
}
items.append(contentsOf: [previousButton, nextButton])
}
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: view, action: #selector(UIView.endEditing))
items.append(contentsOf: [spacer, doneButton])
toolbar.setItems(items, animated: false)
textField.inputAccessoryView = toolbar
}
}
}
I am calling this from other class as :
let field1 = UITextField()
let field2 = UITextField()
addInputAccessoryForTextFields([field1, field2], dismissable: true, previousNextable: true)
Although I'm not 100% convinced I understand your question, here goes:
From other classes, you want to call the actions of your buttons, but your actions are set to UITextField.becomeFirstResponder and UIView.endEditing.
Rather than call these methods directly, create your own methods the actions should call, and put these calls into those methods.
In addInputAccessoryForTextFields(...) change the previousButton's target and action to:
previousButton.target = self
previousButton.action = #selector(handlePreviousButton)
Now add the new method:
#objc func handlePreviousButton()
{
// you'll need to associate the previous button to a specific text field
// and hang onto that association in your class, such as in a property named textFieldRelatedToPreviousButton.
self.textFieldRelatedToPreviousButton.becomeFirstResponder()
}
Now you can call handlePreviousButton() directly from elsewhere in your class, if you wish, or even from other classes.
Update
I just noticed you're extending UIViewController. So you can't add storage by adding a property. You can add storage via objc_setAssociatedObject and then get it via objc_getAssociatedObject, however, to get around this. See this SO or this SO for details on that. So you can, for example, "attach" the textField to your previousButton so that you can access it via the handlePreviousButton() method you add to your extension. And you can pass in the previousButton as a parameter (the sender) to handlePreviousButton() too.
Update 2
Another approach to consider is to use the button's tag property to store the tag value of the related textField. (i.e. each button and its related textField would have the same tag value). So in handlePreviousButton(sender:UIBarButtonItem) you loop through all the UITextField children of your self.view and locate the one whose tag matches sender.tag . Then you can do what you need to that UITextField.
Scope
iOS: 10.0
Eureka: 3.0
How to configure properties of the presented view on eg: MultipleSelectorRow<T>?
Code
From the Example project, here's one MultipleSelectorRow
<<< MultipleSelectorRow<Emoji>() {
$0.title = "MultipleSelectorRow"
$0.options = [💁🏻, 🍐, 👦🏼, 🐗, 🐼, 🐻]
$0.value = [👦🏼, 🍐, 🐗]
}.onPresent { from, to in
to.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: from, action: #selector(RowsExampleViewController.multipleSelectorDone(_:)))
}.cellSetup { cell, row in
cell.tintColor = .orange
}
This code produces a selector view where the tint is default, rather than whatever the tint can be setup for the Row's cell itself (in this case, .orange):
The solution is to configure the presented VC in the onPresent callback. There are more things that can be configured, just need to dive in to the classes.
Configuration
Simply define selectableRowCellSetup in a similar way to [cellSetup][1]
...
.onPresent { from, to in
to.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: from, action: #selector(RowsExampleViewController.multipleSelectorDone(_:)))
to.selectableRowCellSetup = { cell, row in
cell.tintColor = .red
}
}
...
Result