jobandtalent / AnimatedTextInput

Animated UITextField and UITextView replacement for iOS
MIT License
760 stars 128 forks source link

Input Accessory Toolbar #37

Closed cesarmtz93 closed 7 years ago

cesarmtz93 commented 7 years ago

I´ve been trying to implement toolbar for numeric keyboard since it doesn't have a return button, and i need it for my form

textInputs[0].type = .numeric
textInputs[0].inputAccessoryView = toolBar

at the moment of doing this is not setting the toolbar and it´s causing an error any ideas?

victorBaro commented 7 years ago

Hello @cesarmtz93 We use input accessory views in JT app with this control without any problems.

Maybe you can try to return your toolbar view in the view controller:

 class YourViewController: UIViewController {

// other stuff
    override var inputAccessoryView: UIView? {
            return toolbar
     }
cesarmtz93 commented 7 years ago

Hi @victorBaro

this is the error that it´s throwing me

Cannot assign to property: 'inputAccessoryView' is a get-only property

and here´s my code

        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
        doneToolbar.barStyle       = UIBarStyle.default
        let flexSpace              = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem  = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(animatedTextInputShouldReturn))

        var items = [UIBarButtonItem]()
        items.append(flexSpace)
        items.append(done)

        doneToolbar.items = items
        doneToolbar.sizeToFit()

        textInputs[2].placeHolderText = NSLocalizedString("Price", comment: "")
        textInputs[2].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[2].delegate = self
        textInputs[2].tag = 2
        textInputs[2].type = .numeric
        textInputs[2].inputAccessoryView = doneToolbar

I don't really know what´s going on, but I do really appreciate the help!

victorBaro commented 7 years ago

Yes, you won't be able to set textInput's inputAccessoryView. You have to override your UIViewController property.

class YourViewController: UIViewController {

    override var inputAccessoryView: UIView? {
        let doneToolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
        doneToolbar.barStyle = UIBarStyle.default
        let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        let done: UIBarButtonItem  = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(animatedTextInputShouldReturn))
        let items = [flexSpace, done]
        doneToolbar.items = items
        return doneToolbar
     }

    func viewDidLoad() {
        textInputs[2].placeHolderText = NSLocalizedString("Price", comment: "")
        textInputs[2].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[2].delegate = self
        textInputs[2].tag = 2
        textInputs[2].type = .numeric

// DO NOT SET THIS DIRECTLY
//        textInputs[2].inputAccessoryView = doneToolbar
    }
}
cesarmtz93 commented 7 years ago

@victorBaro

seem a good solution but now in the delegate method i cannot get the tag number since mi initial setup is

textInputs[0].placeHolderText = NSLocalizedString("Product Name", comment: "")
        textInputs[0].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[0].delegate = self
        textInputs[0].tag = 0

        textInputs[1].placeHolderText = NSLocalizedString("Category", comment: "")
        textInputs[1].type = .selection
        textInputs[1].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[1].delegate = self
        textInputs[1].tapAction = { [weak self] in
            guard let strongself = self else { return }
            strongself.createPickerView()
            self?.view.endEditing(true)
            self?.scrollView.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
        }

        textInputs[2].placeHolderText = NSLocalizedString("Price", comment: "")
        textInputs[2].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[2].delegate = self
        textInputs[2].tag = 1
        textInputs[2].type = .numeric

    func animatedTextInputShouldReturn(animatedTextInput: AnimatedTextInput) -> Bool {
        let view = self.view.viewWithTag(animatedTextInput.tag + 1)

        if view == nil {
            //_ = animatedTextInput.resignFirstResponder()
            self.view.endEditing(true)
            scrollView.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
        } else {
            view?.becomeFirstResponder()
        }

        return true
    }

noticed i have already implemented the override of the inputAccessoryView

since the toolbar it's sending it self i'm guessing that self is the tool bar not the text input itself

victorBaro commented 7 years ago

I don't understand the problem. What do you mean by since the toolbar it's sending it self i'm guessing that self is the tool bar not the text input itself? self is your view controller.

Also, what are you trying to achieve? Move from one textInput to the next? If that's what you are trying to do, yo don't need to use tags. You could do something like...

    private var currentInputIndex: Int = 0

    func viewDidLoad() {
        textInputs[0].placeHolderText = NSLocalizedString("Product Name", comment: "")
        textInputs[0].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[0].delegate = self
        textInputs[0].tag = 0

        textInputs[1].placeHolderText = NSLocalizedString("Category", comment: "")
        textInputs[1].type = .selection
        textInputs[1].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[1].delegate = self
        textInputs[1].tapAction = { [weak self] in
            guard let strongself = self else { return }
            strongself.createPickerView()
            self?.view.endEditing(true)
            self?.scrollView.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
        }

        textInputs[2].placeHolderText = NSLocalizedString("Price", comment: "")
        textInputs[2].style = CustomTextInputStyleFullWhite() as AnimatedTextInputStyle
        textInputs[2].delegate = self
        textInputs[2].tag = 1
        textInputs[2].type = .numeric
    }

    func animatedTextInputDidBeginEditing(animatedTextInput: AnimatedTextInput) {
        guard let index = textInputs.index(of: animatedTextInput) else { return }
        currentInputIndex = index
    }

    func animatedTextInputShouldReturn(animatedTextInput: AnimatedTextInput) -> Bool {
        if currentInputIndex == textInputs.count {
            //Last text input
            self.view.endEditing(true)
            scrollView.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
        } else {
            textInputs[index]?.becomeFirstResponder()
        }
        return true
    }

I am closing this issue. I think it was solved with my previous comment. Reopen if needed.

cesarmtz93 commented 7 years ago

@victorBaro thanks for the help! one last question by doing this, the toolbar will get set to all of the textInputs is there a way to only set it to a certain textInput?

victorBaro commented 7 years ago

Mmmmm yeah I feel like we should do something about that. I am about to generate a new release, I will try to look into that. I think we should add inputView and inputAccessoryView to the textinput. In the meantime, have you tried to return different views on the inputAccessoryView based on the current first responder?

cesarmtz93 commented 7 years ago

@victorBaro yeah actually i ended up doing that, but i just wanted to highlight that it would add the toolbar to all the fields, like you said it´s just something that might want to check out for the next release,

also one quick question, will you be adding other text inputs in the new release e.g. phonePad maybe?

Thanks for the help!

victorBaro commented 7 years ago

@cesarmtz93 take a look here

Also, there is a numericType. You can create more keyboards (phonePad) if needed.