4

我有一个简单的 UIViewController,我正在尝试学习如何配置 MDCTextField。

我有两个错误

  1. 文本字段不可编辑
  2. 帮助文本显示在文本字段的顶部而不是其下方。

如何解决这两个错误?或者这种文本字段是否有更好的库。

这里是我们点击它之前的文本字段。您可以看到帮助文本位于文本字段的顶部。

在此处输入图像描述

这是单击后的文本字段。 您可以看到占位符文本确实浮动并且占位符文本和下划线确实改变了颜色,但我仍然无法输入文本并且帮助文本仍然在顶部而不是在下方。

在此处输入图像描述

这是示例代码

let leftpad: CGFloat = 16

import UIKit
import MaterialComponents.MaterialTextFields

class ViewController: UIViewController, UIScrollViewDelegate {  // ,   UITextFieldDelegate

var containerHeight : CGFloat = 1000
let scrollView = UIScrollView()
var textFieldFloating : MDCTextField!
var textFieldControllerFloating = MDCTextInputControllerUnderline()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    // Container
    containerView.delegate = self
    view.addSubview(containerView)
    containerView.contentSize = CGSize(width: view.frame.width, height: containerHeight)
    containerView.autoresizingMask = UIViewAutoresizing.flexibleBottomMargin
    containerView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
    containerView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
    containerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: 0).isActive = true
    containerView.heightAnchor.constraint(equalTo: view.heightAnchor, constant: 0).isActive = true

    // Text
    textFieldFloating = MDCTextField()
    textFieldFloating.translatesAutoresizingMaskIntoConstraints = false
    // textFieldFloating.delegate = self
    textFieldFloating.placeholder = "Name"
    textFieldFloating.isEnabled = true
    textFieldFloating.isUserInteractionEnabled = true
    textFieldFloating.clearButtonMode = .whileEditing
    textFieldControllerFloating = MDCTextInputControllerUnderline(textInput: textFieldFloating)
    textFieldControllerFloating.helperText = "Enter a name"
    textFieldControllerFloating.leadingUnderlineLabelTextColor = UIColor.darkGray       // The helper text
    textFieldControllerFloating.trailingUnderlineLabelTextColor = UIColor.green
    textFieldControllerFloating.inlinePlaceholderColor = UIColor.lightGray              // inline label
    textFieldControllerFloating.borderFillColor = UIColor.white
    textFieldControllerFloating.isFloatingEnabled = true

    textFieldControllerFloating.activeColor = UIColor.orange                            // active label & underline
    textFieldControllerFloating.normalColor = UIColor.lightGray                         // default underline
    textFieldControllerFloating.errorColor = UIColor.red
    // textFieldControllerFloating.floatingPlaceholderNormalColor = UIColor.magenta

    containerView.addSubview(textFieldFloating)

}

override func viewDidLayoutSubviews() {

    // containerView.view.layout( textFieldFloating).center().left(leftpad).right(leftpad)
    textFieldFloating.topAnchor.constraint(equalTo: containerView.topAnchor, constant : 40 ).isActive = true
    textFieldFloating.leftAnchor.constraint(equalTo: containerView.leftAnchor, constant : leftpad ).isActive = true
    textFieldFloating.widthAnchor.constraint(equalTo: containerView.widthAnchor, constant : -leftpad * 2).isActive = true
    textFieldFloating.heightAnchor.constraint(equalToConstant: 40).isActive = true
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


// The container
let containerView: UIScrollView = {
    let view = UIScrollView()
    view.backgroundColor = UIColor.white
    view.translatesAutoresizingMaskIntoConstraints = false
    view.layer.masksToBounds = true                          // This makes the rounded corners visible
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleContainerTap))
    view.isUserInteractionEnabled = true
    view.addGestureRecognizer(tapGestureRecognizer)
    return view
}()
@objc func handleContainerTap() {
    resignFirstResponderListOnContainerTap()
}
func resignFirstResponderListOnContainerTap() {
    // tfName.resignFirstResponder()
}



}
4

2 回答 2

4

尝试删除 MDCTextfield 的高度约束。我也遇到了同样的问题,并在删除高度约束后得到了修复,因为 MDCTexfield 需要它自己的高度才能正常运行。

于 2019-03-15T09:14:27.337 回答
0

在花了太多时间尝试为简单的 textField 设置 MDCTextField 之后,我决定开发自己的子类,其中 i) 上边缘的动画占位符,ii) 信息标签和 iii) 底部的动画线。

它是 UITextField 的子类,因此使用 UITextFieldDelegate 方法一切正常

使用textField.placehoderText = "Placeholder"textfield.infolabel.text = "Warning"设置辅助文本。动画是自动的。

passwordTextField = AGTextField()
passwordTextField.delegate = self
passwordTextField.autocapitalizationType = .none
passwordTextField.keyboardType = UIKeyboardType.default
passwordTextField.isSecureTextEntry = true
passwordTextField.placehoderText = "Password"
self.view.addSubview(passwordTextField)
passwordTextField.addAnchorsAndCenter(centerX: true, centerY: nil, width: width, height: 30, left: nil, top: 30, right: nil, bottom: nil, withAnchor: .top, relativeToView: emailTextField)

附加子类和自动布局助手

import UIKit
class AGTextField: UITextField {
    var animationDuration: TimeInterval = 0.3
    var placehoderText: String = "" {
        didSet {
            placeholderLabel.text = placehoderText
        }
    }
    var placeholderLabel: UILabel!
    var infoLabel: UILabel!
    var activeColor: UIColor = .gray {
        didSet {
            line.backgroundColor = activeColor
        }
    }
    private let placeholderColor = UIColor.gray
    private let infoColor = UIColor.red
    private var line: UIView!
    convenience init() {
        self.init(frame: CGRect.zero)
        self.tintColor = activeColor
        self.font = UIFont(name: Fonts.regular, size: 16)
        line = UIView()
        line.backgroundColor = activeColor
        self.addSubview(line)
        line.addAnchorsAndSize(width: nil, height: 1.5, left: 0, top: nil, right: 0, bottom: 0)
        placeholderLabel = UILabel()
        placeholderLabel.font = UIFont(name: Fonts.regular, size: 16)
        placeholderLabel.textColor = .lightGray
        self.addSubview(placeholderLabel)
        Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { (nil) in
            self.placeholderLabel.frame = self.bounds
        }
        infoLabel = UILabel()
        infoLabel.font = UIFont(name: Fonts.regular, size: 12)
        infoLabel.textColor = .red
        infoLabel.isHidden = true
        self.addSubview(infoLabel)
        infoLabel.addAnchors(left: 0, top: 8, right: nil, bottom: nil, withAnchor: .top, relativeToView: line)
        NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidBeginEditing(notification:)), name: NSNotification.Name.UITextFieldTextDidBeginEditing, object: self)
        NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidEndEditing(notification:)), name: NSNotification.Name.UITextFieldTextDidEndEditing, object: self)
    }
    @objc func textFieldDidBeginEditing(notification: Notification) {
        UIView.animate(withDuration: animationDuration) {
            self.placeholderLabel.frame.origin.y = self.line.frame.origin.y - 50.0
            self.placeholderLabel.font = UIFont(name: Fonts.regular, size: 12)
            self.line.backgroundColor = .gray
        }
        line.backgroundColor = Colors.accent
        infoLabel.isHidden = true
    }
    @objc func textFieldDidEndEditing(notification: Notification) {
        if self.text?.count == 0 {
            UIView.animate(withDuration: animationDuration) {
                self.placeholderLabel.frame = self.bounds
                self.placeholderLabel.font = UIFont(name: Fonts.regular, size: 16)
            }
        }
        self.line.backgroundColor = .gray
    }
    func showInfo(_ text: String) {
        infoLabel.text = text
        infoLabel.isHidden = false
    }
    func hideInfo() {
        infoLabel.isHidden = true
    }
}

我还添加了我的自动布局 UIView 扩展

import UIKit
enum Anchor { case left, top, right, bottom }
extension UIView {
    /**
    Description: Centers the view in the superview, using the superview's **size** and **XYAxis** position, not the left, top, right, bottom anchors to avoid issues with the *UISCrollViews*
    Parameters: None
    */
    func addAnchorsCenterAndFillContainer() {
        self.translatesAutoresizingMaskIntoConstraints = false
        self.widthAnchor.constraint(equalTo: self.superview!.widthAnchor).isActive = true
        self.heightAnchor.constraint(equalTo: self.superview!.heightAnchor).isActive = true
        self.centerXAnchor.constraint(equalTo: self.superview!.centerXAnchor).isActive = true
        self.centerYAnchor.constraint(equalTo: self.superview!.centerYAnchor).isActive = true
    }

    /**
    Adds 2 optional alignment parameterts (**centerX**, **centerY**), 2 optional size dimensions (**width** and **height**) and up to 4 border anchors **.left**, **.top**, **.right** and **.bottom**. One of them (defined in **withAnchor** can be relative to another view

    - Parameter centerX: **Bool** value (or *nil*) to define if the view should be centered **horizontally** to the superview. (optional)
    - Parameter centerY: **Bool** value (or *nil*) to define if the view should be centered **vertically** to the superview. (optional)
    - Parameter width: The **width** of the view (optional)
    - Parameter width: The **width** of the view (optional)
    - Parameter height: The **height** of the view (optional)
    - Parameter left: The **left** margin to the superview
    - Parameter top: The **top** margin to the superview
    - Parameter right: The **right** margin to the superview. *Magniture adjusted to be positive for margins inside the view*
    - Parameter bottom: The **bottom** margin to the superview. *Magniture adjusted to be positive for margins inside the view*
    - Parameter withAnchor: The **Anchor** type that is relative to the **relativeToView** view. *This parameter can be omited*
    - Parameter relativeToView: The **UIView** object that is the reference for the **withAnchor** anchor. *This parameter can be omited*

    - Returns: None
    */
    func addAnchorsAndCenter(centerX: Bool?, centerY: Bool?, width: CGFloat?, height: CGFloat?, left: CGFloat?, top: CGFloat?, right: CGFloat?, bottom: CGFloat?, withAnchor: Anchor? = nil, relativeToView: UIView? = nil) {

        self.translatesAutoresizingMaskIntoConstraints = false
        if centerX != nil {
            if centerX! == true {
                self.centerXAnchor.constraint(equalTo: self.superview!.centerXAnchor).isActive = true
            }
        }
        if centerY != nil {
            if centerY! == true {
                self.centerYAnchor.constraint(equalTo: self.superview!.centerYAnchor).isActive = true
            }
        }

        self.addAnchorsAndSize(width: width, height: height, left: left, top: top, right: right, bottom: bottom, withAnchor: withAnchor, relativeToView: relativeToView)
    }

    /**
    Adds 2 optional size dimensions (**width** and **height**) and up to 4 border anchors **.left**, **.top**, **.right** and **.bottom**. One of them (defined in **withAnchor** can be relative to another view

    - Parameter width: The **width** of the view (optional)
    - Parameter height: The **height** of the view (optional)
    - Parameter left: The **left** margin to the superview
    - Parameter top: The **top** margin to the superview
    - Parameter right: The **right** margin to the superview. *Magniture adjusted to be positive for margins inside the view*
    - Parameter bottom: The **bottom** margin to the superview. *Magniture adjusted to be positive for margins inside the view*
    - Parameter withAnchor: The **Anchor** type that is relative to the **relativeToView** view. *This parameter can be omited*
    - Parameter relativeToView: The **UIView** object that is the reference for the **withAnchor** anchor. *This parameter can be omited*

    - Returns: None
    */
    func addAnchorsAndSize(width: CGFloat?, height: CGFloat?, left: CGFloat?, top: CGFloat?, right: CGFloat?, bottom: CGFloat?, withAnchor: Anchor? = nil, relativeToView: UIView? = nil) {

        self.translatesAutoresizingMaskIntoConstraints = false
        if width != nil {
            self.widthAnchor.constraint(equalToConstant: width!).isActive = true
        }
        if height != nil {
            self.heightAnchor.constraint(equalToConstant: height!).isActive = true
        }
        self.addAnchors(left: left, top: top, right: right, bottom: bottom, withAnchor: withAnchor, relativeToView: relativeToView)
    }

    /**
    Adds up to 4 border anchors **.left**, **.top**, **.right** and **.bottom**. One of them (defined in **withAnchor** can be relative to another view

    - Parameter left: The **left** margin to the superview
    - Parameter top: The **top** margin to the superview
    - Parameter right: The **right** margin to the superview. *Magniture adjusted to be positive for margins inside the view*
    - Parameter bottom: The **bottom** margin to the superview. *Magniture adjusted to be positive for margins inside the view*
    - Parameter withAnchor: The **Anchor** type that is relative to the **relativeToView** view. *This parameter can be omited*
    - Parameter relativeToView: The **UIView** object that is the reference for the **withAnchor** anchor. *This parameter can be omited*

    - Returns: None
    */
    func addAnchors(left: CGFloat?, top: CGFloat?, right: CGFloat?, bottom: CGFloat?, withAnchor: Anchor? = nil, relativeToView: UIView? = nil) {

        self.translatesAutoresizingMaskIntoConstraints = false
        let superView = self.superview!
        if withAnchor != nil && relativeToView != nil {
            /**
            * Anchors relative to oposite anchors of reference view
            **/
            switch withAnchor! {
            case .left:
                if left != nil {
                    self.leftAnchor.constraint(equalTo: relativeToView!.rightAnchor, constant: left!).isActive = true
                }
            case .top:
                if top != nil {
                    self.topAnchor.constraint(equalTo: relativeToView!.bottomAnchor, constant: top!).isActive = true
                }
            case .right:
                if right != nil {
                    self.rightAnchor.constraint(equalTo: relativeToView!.leftAnchor, constant: -right!).isActive = true
                }
            case .bottom:
                if bottom != nil {
                    self.bottomAnchor.constraint(equalTo: relativeToView!.topAnchor, constant: -bottom!).isActive = true
                }
            }
        }

        /**
        * Anchors relative to same anchors of superview
        **/
        if let _anchor = withAnchor {
            if _anchor == .left {
                if top != nil {
                    self.topAnchor.constraint(equalTo: superView.topAnchor, constant: top!).isActive = true
                }
                if right != nil {
                    self.rightAnchor.constraint(equalTo: superView.rightAnchor, constant: -right!).isActive = true
                }
                if bottom != nil {
                    self.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: -bottom!).isActive = true
                }
            }
            if _anchor == .top {
                if left != nil {
                    self.leftAnchor.constraint(equalTo: superView.leftAnchor, constant: left!).isActive = true
                }
                if right != nil {
                    self.rightAnchor.constraint(equalTo: superView.rightAnchor, constant: -right!).isActive = true
                }
                if bottom != nil {
                    self.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: -bottom!).isActive = true
                }
            }
            if _anchor == .right {
                if left != nil {
                    self.leftAnchor.constraint(equalTo: superView.leftAnchor, constant: left!).isActive = true
                }
                if top != nil {
                    self.topAnchor.constraint(equalTo: superView.topAnchor, constant: top!).isActive = true
                }
                if bottom != nil {
                    self.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: -bottom!).isActive = true
                }
            }
            if _anchor == .bottom {
                if left != nil {
                    self.leftAnchor.constraint(equalTo: superView.leftAnchor, constant: (left!)).isActive = true
                }
                if top != nil {
                    self.topAnchor.constraint(equalTo: superView.topAnchor, constant: top!).isActive = true
                }
                if right != nil {
                    self.rightAnchor.constraint(equalTo: superView.rightAnchor, constant: -right!).isActive = true
                }
            }
        } else {
            if left != nil {
                self.leftAnchor.constraint(equalTo: superView.leftAnchor, constant: left!).isActive = true
            }
            if top != nil {
                self.topAnchor.constraint(equalTo: superView.topAnchor, constant: top!).isActive = true
            }
            if right != nil {
                self.rightAnchor.constraint(equalTo: superView.rightAnchor, constant: -right!).isActive = true
            }
            if bottom != nil {
                self.bottomAnchor.constraint(equalTo: superView.bottomAnchor, constant: -bottom!).isActive = true
            }
        }
    }
}
于 2018-09-04T20:13:16.363 回答