Material icon indicating copy to clipboard operation
Material copied to clipboard

Add TextField to Dialog

Open leedsalex opened this issue 6 years ago • 9 comments

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.

leedsalex avatar Apr 18 '19 19:04 leedsalex

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.

OrkhanAlikhanov avatar Apr 18 '19 22:04 OrkhanAlikhanov

Definitely can see how this would be useful :)

daniel-jonathan avatar Apr 18 '19 23:04 daniel-jonathan

@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 avatar Apr 19 '19 04:04 leedsalex

@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!

OrkhanAlikhanov avatar Apr 22 '19 16:04 OrkhanAlikhanov

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.

OrkhanAlikhanov avatar Apr 22 '19 16:04 OrkhanAlikhanov

@leedsalex @OrkhanAlikhanov nice work! Let's leave this open for now. I would like to dive in this myself as well.

daniel-jonathan avatar Apr 22 '19 17:04 daniel-jonathan

@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 avatar Sep 08 '19 13:09 adamdahan

@adamdahan fully agree.

daniel-jonathan avatar Sep 08 '19 14:09 daniel-jonathan

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.

jbaez avatar Oct 10 '19 08:10 jbaez