如何创建具有占位符,多行和垂直居中的UitextView或Uitextfield



我想要的是一个非常直观的事情,但令人惊讶的是,它未包含在xcode中:我想要的是具有

的文本视图或文本字段

1-占位符
2-几行(如UITEXTVIEW中的滚动视图(。
3-文本或占位符应始终垂直和水平为中心。

我研究了类似的问题:
中心文本在UITEXTVIEW中垂直
将文本置于垂直和水平的UITEXTVIEW中
在uitextview

中垂直对齐文本中心

对于占位符,我正在使用以下库:
https://github.com/devxoul/uitextview-placeholder哪个解决了第一个要求,但即使上面的链接中给出的答案,我也无法满足其他2个要求

我正在使用Swift 3.1,部署目标ios9,Xcode 8.3.2

不幸的是,UITextViewUITextField都如此有限。许多开发人员已经多次完成了这些事情。

我通常要做的就是创建一个新的UIView子类,然后具有2个子视图。占位符和集中文本视图的标签。

您可以在XIB中进行操作并使用接口构建器,我建议您这样做。然后,您可以公开文本视图和占位符,实际上可以设置几乎所有您需要的东西。

,但是要在代码中进行,它看起来像以下内容:

@IBDesignable class CustomTextView: UIView {
    private(set) var textView: UITextView = UITextView(frame: CGRect.zero)
    private(set) var placeholderLabel: UILabel = UILabel(frame: CGRect.zero)
    @IBInspectable var placeholder: String? {
        didSet {
            placeholderLabel.text = placeholder
        }
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    private func setup() {
        textView.delegate = self
        addSubview(textView)
        textView.backgroundColor = UIColor.clear
        textView.textAlignment = .center
        addSubview(placeholderLabel)
        placeholderLabel.textAlignment = .center
        placeholderLabel.numberOfLines = 0
        addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap)))
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        refreshViews()
    }
    fileprivate func refreshViews() {
        UIView.performWithoutAnimation {
            textView.frame = self.bounds
            let optimalSize = textView.sizeThatFits(bounds.size)
            textView.frame = CGRect(x: 0.0, y: max((bounds.size.height-optimalSize.height)*0.5, 0.0), width: bounds.width, height: min(optimalSize.height, bounds.size.height))
            placeholderLabel.frame = bounds
            placeholderLabel.backgroundColor = UIColor.clear
            if textView.text.isEmpty && textView.isFirstResponder == false {
                placeholderLabel.text = placeholder
                placeholderLabel.isHidden = false
                textView.isHidden = true
            } else {
                placeholderLabel.isHidden = true
                textView.isHidden = false
            }
        }
    }
    @objc private func onTap() {
        if !textView.isFirstResponder {
            textView.becomeFirstResponder()
        }
    }
}
extension CustomTextView: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        refreshViews()
    }
    func textViewDidBeginEditing(_ textView: UITextView) {
        refreshViews()
    }
    func textViewDidEndEditing(_ textView: UITextView) {
        refreshViews()
    }
}

仍然有一些弊端:

  1. 视图本身需要文本视图的代表。因此,如果您在某些视图控制器中调用myView.textView.delegate = self,则会打破内部的逻辑。如果您需要它,我建议您在此视图上创建一个自定义委托,并公开所需的方法,而不是标准UITextViewDelegate
  2. 尽管课程是可设计的,但您无法拥有许多可检查的字段。因此,很难在接口构建器内部设置任何属性。您可以揭露诸如"文本"之类的属性,并将setter和getter指向文本视图。对于文本颜色也可以做同样的事情...但是最大的问题是您无法将字体标记为可检查的字体(我猜是哭泣(。
  3. 在某些情况下,文本进入Newline时会跳一些。我想您需要玩一些才能完善它。可能的约束可能会解决此问题,因此,如果您在XIB中进行操作可以解决它。

是一件好事,尽管您可以从代码中做任何事情。多行或属性的字符串占位符,对准,颜色,字体...

实际上我感到有些愚蠢,因为答案一直是我的眼前...

对于占位符,我将只使用图书馆:https://github.com/devxoul/uitextview-placeholder在我的问题中提到

然后在uiviewController类中我做了以下操作:

class myClass: UIViewController {
      @IBOutlet weak var myTextView: UITextView!
      override func viewDidLoad() {
          super.viewDidLoad()
          // Set the textView to the Delegate 
          myTextView.delegate = self
          // Initialize the textView text Position and accordingly the
          //   placeholder position 
          myTextView.contentInset.top = max(0, (tv_comment.bounds.size.height - tv_comment.contentSize.height * tv_comment.zoomScale) / 2)
      }
       extension myClass: UITextViewDelegate {
              func textViewDidChange(_ textView: UITextView) {
                   // do the same adjustment again every time the textView changes
                   textView.contentInset.top = max(0, (textView.bounds.size.height - textView.contentSize.height * textView.zoomScale) / 2)
              }
       }

最新更新