Material
Material copied to clipboard
Add TextField to Dialog
Would be nice to have a TextField in a Dialog. I have achieved this by subclassing DialogView but I feel it's something others can benefit from if it was built-in.
Hey! Great idea! Would be great if you share your subclass and/or your use case. So that we have some insight about what users need.
Definitely can see how this would be useful :)
@OrkhanAlikhanov Here's the subclass in its most basic form. Keep in mind it's a bit amiss, I had to work with the open methods available to me. It would have been a little cleaner if Dialog was generic similar to DialogController, and if DialogView's layout and prepare methods were open instead of private. Also, I chose an arbitrary size for example purposes.
DialogView Subclass
class DialogTextFieldView: DialogView {
let textField: ErrorTextField = {
let textField = ErrorTextField()
textField.validator.min(length: 1, message: "Min 0 characters").max(length: 30, message: "Max 30 characters").autoValidationType = .always
textField.placeholder = "Example Input"
textField.placeholderAnimation = .hidden
return textField
}()
override func prepare() {
super.prepare()
detailsLabel.removeFromSuperview()
contentArea.addSubview(textField)
}
override func layoutSubviews() {
layoutContentArea()
super.layoutSubviews()
}
override func contentAreaSizeThatFits(width: CGFloat) -> CGSize {
return CGSize(width: width, height: 60)
}
func layoutContentArea() {
let size = CGSize(width: frame.width, height: contentAreaSizeThatFits(width: frame.width).height)
contentArea.frame.size = size
let insets = titleArea.frame.height == 0 ? UIEdgeInsets(top: 20, left: 24, bottom: 24, right: 24) : UIEdgeInsets(top: 0, left: 24, bottom: 24, right: 24)
textField.frame = CGRect(origin: .zero, size: size).inset(by: insets)
}
}
Presentation Setup
Note: I couldn't use the Dialog class with a custom view/controller
let controller = DialogController<DialogTextFieldView>()
controller.dialogView.titleLabel.text = "TextField Example"
controller.dialogView.positiveButton.title = "Save"
controller.dialogView.positiveButton.titleColor = Color.green.base
controller.dialogView.neutralButton.title = "Cancel"
controller.dialogView.neutralButton.titleColor = Color.grey.base
controller.dialogView.textField.dividerActiveColor = Color.grey.base
present(controller, animated: true)
@leedsalex Thank you for your feedback on Material's Dialog
It would have been a little cleaner if Dialog was generic similar to
DialogController
It was like that once, but we had to compromise it in favor of DialogDelegate.
Will work on the API. Thank you!
By the way, it's nice to see someone is diving into the source to learn and use Material's new features which has no documentation whatsoever except in the pull requests that introduced the feature.
@leedsalex @OrkhanAlikhanov nice work! Let's leave this open for now. I would like to dive in this myself as well.
@danieldahan @OrkhanAlikhanov Let's try to get this in for Material 4. :) @leedsalex thanks, good addition! Now that we are aware of it. We will massage it into the code base for our next updates.
@adamdahan fully agree.
This is a very good idea, I recently updated Material and saw that dialogs are available, and started migrating UIAlert to Material Dialog.
In the DialogTextFieldView I added the method addTextField like in UIAlertController, so we can add more than one text field.
public var textFields: [TextField] = []
public func addTextField(configurationHandler: ((TextField) -> Void)? = nil) {
let textField = TextField()
textFields.append(textField)
contentArea.addSubview(textField)
if let configurationHandler = configurationHandler {
configurationHandler(textField)
}
}
Also will have to create another subclass to be able to add more buttons, In the App I'm working on we have a UIAlert with four buttons and the Material Dialog only has 3 configurable buttons.