Add uipickerview stored in object to viewcontroller's view - swift

Many people on SO suggest using a uipickerview and a uitextfield to make a dropdown-like interface. I having a pickerview stored in an object. How can I then add this to a viewcontroller's view when the textfield is tapped?

Instead of storing the pickerview, store only the datasource in the dropdown class. Make the ViewController the delegate of the dropdown class. When the textfield begins editing, call a delegate method to set the datasource of the pickerview the the viewcontroller to the dropdown
Dropdown Delegate protocol:
protocol DropdownDelegate : class {
func activateDropdown(dropdown: Dropdown)
}
Dropdown class:
class Dropdown: UITextField, UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate {
var dataSouce : String = []
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == self {
if(dropdownDelegate != nil) {
dropdownDelegate?.activateDropdown(dropdown: self)
textField.endEditing(true)
}
}
}
//rest of delegate methods
}
ViewController class
class ViewController: UIViewController, DropdownDelegate {
#IBOutlet weak var pickerView: UIPickerView!
func activateDropdown(dropdown: Dropdown) {
self.pickerView.delegate = dropdown
self.pickerView.dataSource = dropdown
}
func deactivateDropdown() {
changeDropdownStatus(status: true)
self.pickerView.isHidden = true
}
}

Related

Is it possible to modify the properties of a subclass from a parent class in Swift 4?

Via a method or closure, perhaps?
I created a subclass view controller of my superclass/parent view controller and placed labels with placeholder text in that subclass view controller.
I want to set the labels' values to blank strings from the superclass/parent view controller, or, specifically, from an IBAction function that causes the subclass view controller to appear.
Here is the code, first from the parent class, then from the subclass...
'''
class ViewController: UIViewController {
#IBAction func leavingView(){
self.EntryViewController.entryDateLabel.text = ""
self.EntryViewController.entryLabel.text = ""
self.dismiss(animated: true, completion: nil)
}
'''
then from the subclass...
'''
class EntryViewController: ViewController {
#IBOutlet var entryDateLabel: UILabel!
#IBOutlet var entryLabel: UILabel!
}
'''
I have come up with 2 solutions to this problem, without having the parent view controller know about its subclass.
In the first example the parent sets properties on itself that the child listens to (via the didSet method, it then updates its view accordingly. However, this isn't ideal because the entryDate and entry string fields are useless on their own, almost redundant in the parent.
class ParentViewController: UIViewController {
var entryDate: String?
var entry: String?
#IBAction func leavingView(){
self.entryDate = ""
self.entry = ""
self.dismiss(animated: true, completion: nil)
}
}
class ChildViewController: ParentViewController {
#IBOutlet var entryDateLabel: UILabel!
#IBOutlet var entryLabel: UILabel!
override var entryDate: String? {
didSet {
guard isViewLoaded else {
return
}
entryDateLabel.text = entryDate
}
}
override var entry: String? {
didSet {
guard isViewLoaded else {
return
}
entryLabel.text = entry
}
}
}
In my opinion, the second solution is clearer and keeps implementation details more separate because you're using instructions or events to notify the child view controllers.
class ParentViewController: UIViewController {
#IBAction func leavingView(){
self.dismiss(animated: true, completion: didLeaveView)
}
func didLeaveView() { }
}
class ChildViewController: ParentViewController {
#IBOutlet var entryDateLabel: UILabel!
#IBOutlet var entryLabel: UILabel!
override func didLeaveView() {
entryDateLabel.text = ""
entryLabel.text = ""
}
}
Since your requirement is not that much clear I have created a demo for you and into that demo I have added child ContainerViewController into parent ViewController and from that parent view controller you can change UILabel text when you click on UIButton of parent ViewController and code will be for ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnFromParentViewTapped(_ sender: Any) {
//Here get the child of your parent view controller
if let containerView = self.children[0] as? ContainerViewController {
containerView.lblContainer.text = ""
}
}
}
and ContainerViewController code will be:
class ContainerViewController: UIViewController {
#IBOutlet weak var lblContainer: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Don't need to add much here because you are accessing it from parent view.
And your result will be:
As you can see when I click on button which title says Change Container label text the label text from ContainerViewController set to empty string.
For more info check THIS demo project.

#IBDesignable with protocol

I have a UIview xib within a view controller, UIview class have two buttons with protocol function, but the protocol function never called when I press button, storyboard image like below
protocol method like below
import UIKit
#objc protocol TopViewDelegate: NSObjectProtocol {
#objc optional func pressRefreshButton()
#objc optional func pressMenuButton()
}
UIView class
#IBDesignable class OnJob_Top: UIView,TopViewDelegate {
weak var delegate : TopViewDelegate? = nil
#IBAction func refreshButtonTouchUpInside(_ sender: UIButton) {
delegate?.pressRefreshButton!()
}
#IBAction func menuButtonTouchUpInside(_ sender: UIButton) {
delegate?.pressMenuButton!()
print("come come")
}
view controller class
class HomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let topView = OnJob_Top()
topView.delegate = self
}
}
extension HomeViewController:TopViewDelegate {
func pressMenuButton() {
print("come") // never come here
}
func pressRefreshButton() {
print("come") // never come here
}
}
Consider this code:
let topView = OnJob_Top()
topView.delegate = self
In the first line, you create a completely new OnJob_Top view.
In the second line, you make it the delegate.
In the third line... but there is no third line. The view vanishes in a silent puff of smoke. It is useless.
Meanwhile, the view in the storyboard never gets a delegate. So its delegate methods are never called.

UITextFieldDelegate extension function does not triggers, why?

I have SequencedTextFields protocol, which contains sequence of text fields. When user taps Return button on keyboard, current text field should resign first responder and next text field in the sequence should become first responder. And it works good, when I'm using direct implementation of UITextFieldDelegate protocol for view controller:
extension MyViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
nextInSequence(after: textField)?.becomeFirstResponder()
return true
}
}
But, when I'm trying to use default implementation, it does not triggers ever:
extension UITextFieldDelegate where Self: SequencedTextFields {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
nextInSequence(after: textField)?.becomeFirstResponder()
return true
}
}
What could be the reason? Or I've missed something?
UPDATE:
My view controller defining:
final class MyViewController: UIViewController, UITextFieldDelegate, SequencedTextFields
Setting up the delegate for the text fields:
The reason why your implementation is not working is because you are trying to extend an interface (UITextFieldDelegate) instead of a class, that's why it works when you use UIViewController instead.
What you can do is to create a custom class SequencedTextField that extends UITextField. Add a custom delegate (that I called sequencedDelegate that represents the class that implements your SequencedTextFields protocol.
Extend SequencedTextField to implement UITextFieldDelegate with your default implementation.
On MyViewController, set up your SequencedTextField delegate with the viewController itself.
At the end it should look something like this:
protocol SequencedTextFields: class {
func nextInSequence(after: UITextField) -> UITextField?
}
class SequencedTextField: UITextField {
weak var sequencedDelegate: SequencedTextFields?
}
extension SequencedTextField: UITextFieldDelegate {
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
sequencedDelegate?.nextInSequence(after: textField)?.becomeFirstResponder()
return true
}
}
class MyViewController : UIViewController, SequencedTextFields {
var textField = SequencedTextField()
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = textField
textField.sequencedDelegate = self
}
func nextInSequence(after: UITextField) -> UITextField? {
// your view controllers nextInSequence implementation here
}
}
What is wrong with your code?
The first extension is the extension of your view controller MyViewController, that's why it is working. But the second one is the extension of UITextFieldDelegate. Those are completely two different things.
Not clear what you want to achieve.
This is how you can use your custom protocol
If you want to make one CustomProtocol for your special UITextField you can do like this.
CustomTextFieldProtocol
Declear the protocol
protocol SequencedTextFields: UITextFieldDelegate {
func checkSomeThing(_ textField: UITextField) -> Bool
}
Set the delegate
self.textField.delegate = self
ViewController Extension to implement your Delegate methods
extension ViewController: SequencedTextFields {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
nextInSequence(after: textField)?.becomeFirstResponder()
return true
}
func checkSomeThing(_ textField: UITextField) -> Bool {
print("Check here")
return true
}
}

nil value in protocol delegation in tableview and customcell

Im new in Swift, sorry.
I want push value from customcell class to TableViewController class.
But always get "nil".
protocol DetailsDelegate {
func labelDelegateMethodWithString(controller: TableViewController) -> String }
class TableViewController: UITableViewController {
var delegate: DetailsDelegate?
#IBAction func butttonFunc(sender: UIButton) {
let importNumber = delegate!.labelDelegateMethodWithString(self)
println(importNumber)
}
and here my custom cell class:
class TableViewCell: UITableViewCell, UITextFieldDelegate, DetailsDelegate {
func labelDelegateMethodWithString(controller: TableViewController) -> String {
return "efgfsd"
}
What im doing wrong? thanks.

How to add text to an active UITextField

I have a couple of UITextField's and one UIButton. If I tap on the UIButton, I want to place some static text in the active UITextField.
So something like:
#IBAction func buttonEen(sender: UIButton) {
'active textField'.text = "static text"
}
But how do I determine which UITextField is the active UITextField and how do I reach it?
To write text in last active UITextField you have to make your UIViewController a delegate of UITextField
ex:
class ViewController: UIViewController, UITextFieldDelegate
declare a activeField variable
ex:
var activeField: UITextField?
then implements textFieldDidBeginEditing
ex:
func textFieldDidBeginEditing(textField: UITextField)
{
activeField = textField
}
So your button function will be something like
#IBAction func buttonEen(sender: UIButton) {
if activeField
{
activeField.text = "static text"
}
}
First you need to create your textfield delegate (probably in 'ViewDidLoad()') :
activeTxtField.delegate = self
Then you need to implement the textField delegate function:
extension 'YourVC': UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == activeTxtField {
// Do whatever you want
// e.g set textField text to "static text"
}
}
}