[英]How to create a UITextView or a UITextField that has a placeHolder, multiline and vertically centered?
What I want is a very intuitive thing but surprisingly it is not included in Xcode: what I want is a textView or a textField that will have 我想要的是一个非常直观的东西,但是令人惊讶的是它没有包含在Xcode中:我想要的是一个textView或textField,它将具有
1- a placeholder 1-占位符
2- several lines (with scroll view like in UITextView). 2-几行(具有类似UITextView的滚动视图)。
3- either the text or the placeholder should always be vertically and horizontally centered in the textBoxArea . 3-文本或占位符应始终在textBoxArea中垂直和水平居中。
I've looked at similar questions like: 我看过类似的问题,例如:
Center text vertically in a UITextView 在UITextView中垂直居中放置文本
Center the text in a UITextView, vertically and horizontally 将文本在UITextView中垂直和水平居中
Aligning text vertically center in UITextView 在UITextView中垂直居中对齐文本
for the placeHolder I am using the following library: 对于placeHolder,我正在使用以下库:
https://github.com/devxoul/UITextView-Placeholder which solves the first requirement but I couldn't satisfy the other 2 requirements even with the answer given in the links above https://github.com/devxoul/UITextView-Placeholder解决了第一个要求,但是即使上面的链接给出了答案,我也无法满足其他两个要求
I am using swift 3.1, deployment target iOS9, Xcode 8.3.2 我正在使用swift 3.1,部署目标iOS9,Xcode 8.3.2
It is unfortunate that both UITextView
and UITextField
are so limited. 不幸的是, UITextView
和UITextField
是如此有限。 These same things have been done for so many times by so many developers. 许多开发人员已经做过很多次相同的事情。
What I usually do is just create a new UIView
subclass which then has 2 subviews; 我通常要做的就是创建一个新的UIView
子类,然后该子类具有2个子视图。 A label for placeholder and centered text view for content. 占位符的标签和内容的居中文本视图。
You can do it in xib and use the interface builder and I suggest you to do so. 您可以在xib中进行操作,并使用界面构建器,建议您这样做。 You can then expose both text view and placeholder and you may actually set pretty much anything you would ever need. 然后,您可以同时显示文本视图和占位符,并且实际上可以设置几乎所需的任何内容。
But to do it in the code it would look something like the following: 但是要在代码中执行此操作,将类似于以下内容:
@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()
}
}
There are still a few downsides though: 但是仍然存在一些缺点:
myView.textView.delegate = self
in some view controller you would break the logic inside. 因此,如果您在某些视图控制器中调用myView.textView.delegate = self
,则会破坏内部的逻辑。 If you need it I suggest you create a custom delegate on this view and expose the methods you need instead of the standard UITextViewDelegate
. 如果需要,建议您在此视图上创建一个自定义委托,并公开所需的方法,而不是标准的UITextViewDelegate
。 As a good thing though you can do pretty much anything from the code. 幸运的是,您可以从代码中执行几乎所有操作。 Multiline or attributed string placeholders, alignments, colors, fonts... 多行或属性字符串占位符,对齐方式,颜色,字体...
actually I feel a little silly because the answer was infront of my eye all the time ... 实际上我有点傻,因为答案一直都在我的眼前。
For the PlaceHolder I'll just use the library: https://github.com/devxoul/UITextView-Placeholder mentioned in my question 对于PlaceHolder,我将仅使用该库:我的问题中提到的https://github.com/devxoul/UITextView-Placeholder
then in the UIViewController class I did the following: 然后在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)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.