I have subclassed the UITextField class so I can provide some built-in functionality for my application. I've changed the appearance to provide only an underline border for the UX design. Also, I want to use this control in situations where there is a picker (pick list, date / time picker). In these cases, I want to prevent editing BUT I still need to respond to touch events. To do this, I've added inspectable properties to control it from IB.
I can easily prevent the copy/paste menu from appearing by doing this:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if isFirstResponder && disableEditing {
DispatchQueue.main.async(execute: {
(sender as? UIMenuController)?.setMenuVisible(false, animated: false)
})
return false
}
return super.canPerformAction(action, withSender: sender)
}
However, I need to prevent them from typing or deleting characters in the textfield after something is selected in the picker. Typically, you would use the following delegate method:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return false
}
The question is how do you provide this kind of default behavior in a subclass? You could do a:
self.delegate = self
However, this leads to all sorts of shortcomings so it's not a good solution.
The other solution would be to implement a base UIViewController subclass (MyBaseViewController) but this would lead to convoluted and monolithic code later on.
It would be best if there was a clean way to provide this kind of default behavior in an encapsulated manner.
Obviously, there are a number of other ways to fix this (i.e. write the same code in 10 view controllers). Essentially, it seems there should be way to reuse delegate code when subclassing controls like this.
Anyone have any ideas??
Every approach you will take will be a trade-off. I don't think there is a perfectly clean solution for this type of problem. From my point of view, the best solution is to implement your custom
UITextField
as a kind of proxy delegate.You can do it in two ways. This is the simplest one.
If you don't want to modify the delegation interface for your custom control, you can do a small trick and overwrite the
delegate
property.Pros
Cons
The drawback which comes with this approach is that you have to implement every method from the
UITextFieldDelegate
protocol in yourUITextField
subclass to fully support the delegation. Fortunately, there are only 8 of them and it's unlikely that you will need all, so you can narrow it down to the required subset.