을 사용하는 응용 프로그램을 만들고 UITextView
있습니다. 이제 텍스트보기에 텍스트 필드에 설정할 수있는 것과 비슷한 자리 표시자가 필요합니다. Swift를 사용하여 어떻게 이것을 달성 하시겠습니까?
을 사용하는 응용 프로그램을 만들고 UITextView
있습니다. 이제 텍스트보기에 텍스트 필드에 설정할 수있는 것과 비슷한 자리 표시자가 필요합니다. Swift를 사용하여 어떻게 이것을 달성 하시겠습니까?
답변:
스위프트 4 업데이트
UITextView
본질적으로 자리 표시 자 속성이 없으므로 UITextViewDelegate
메서드를 사용하여 프로그래밍 방식으로 속성을 만들고 조작해야 합니다. 원하는 동작에 따라 아래의 솔루션 # 1 또는 # 2를 사용하는 것이 좋습니다.
참고 : 두 솔루션 중 하나 UITextViewDelegate
에 대해 클래스에 추가 textView.delegate = self
하고 텍스트보기의 대리자 메서드를 사용하도록 설정 하십시오.
해결 방법 # 1- 사용자가 텍스트보기를 선택하자마자 자리 표시자가 사라지 길 원하는 경우 :
먼저 UITextView
자리 표시 자 텍스트를 포함 하도록를 설정하고 자리 표시 자 텍스트의 모양을 모방하기 위해 밝은 회색으로 설정합니다 UITextField
. 중 하나에 그렇게 viewDidLoad
하거나 텍스트 뷰의 생성시.
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
그런 다음 사용자가 텍스트보기를 편집하기 시작할 때 텍스트보기에 자리 표시자가 포함 된 경우 (예 : 텍스트 색상이 밝은 회색 인 경우) 자리 표시 자 텍스트를 지우고 사용자 입력을 수용 할 수 있도록 텍스트 색상을 검은 색으로 설정하십시오.
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == UIColor.lightGray {
textView.text = nil
textView.textColor = UIColor.black
}
}
그런 다음 사용자가 텍스트보기 편집을 마치고 첫 번째 응답자로 사임 한 경우, 텍스트보기가 비어 있으면 자리 표시 자 텍스트를 다시 추가하고 색상을 연한 회색으로 설정하여 자리 표시자를 재설정하십시오.
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
}
}
해결 방법 # 2- 텍스트보기가 선택되어 있어도 텍스트보기가 비어있을 때마다 자리 표시자가 표시되도록하려면 :
먼저 다음에 자리 표시자를 설정하십시오 viewDidLoad
.
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
textView.becomeFirstResponder()
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
(참고 : OP는보기가로드되는 즉시 텍스트보기를 선택하기를 원했기 때문에 위의 코드에 텍스트보기 선택을 통합했습니다. 원하는 동작이 아니고보기를로드 할 때 텍스트보기를 선택하지 않으려면, 위의 코드 청크에서 마지막 두 줄을 제거하십시오.)
그런 다음 shouldChangeTextInRange
UITextViewDelegate
방법을 활용하십시오 .
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// Combine the textView text and the replacement text to
// create the updated text string
let currentText:String = textView.text
let updatedText = (currentText as NSString).replacingCharacters(in: range, with: text)
// If updated text view will be empty, add the placeholder
// and set the cursor to the beginning of the text view
if updatedText.isEmpty {
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
// Else if the text view's placeholder is showing and the
// length of the replacement string is greater than 0, set
// the text color to black then set its text to the
// replacement string
else if textView.textColor == UIColor.lightGray && !text.isEmpty {
textView.textColor = UIColor.black
textView.text = text
}
// For every other case, the text should change with the usual
// behavior...
else {
return true
}
// ...otherwise return false since the updates have already
// been made
return false
}
또한 textViewDidChangeSelection
자리 표시자가 표시되는 동안 사용자가 커서 위치를 변경하지 못하도록 구현 합니다. (참고 : textViewDidChangeSelection
뷰가로드되기 전에 호출되므로 창이 표시되는 경우에만 텍스트 뷰의 색상을 확인하십시오) :
func textViewDidChangeSelection(_ textView: UITextView) {
if self.view.window != nil {
if textView.textColor == UIColor.lightGray {
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
}
}
}
yourTextField.delegate = self
. 이 작업을 수행하지 않으면 textViewDidBeginEditing
및 textViewDidEndEditing
기능이 작동하지 않습니다.
Cannot convert value of type 'NSRange' (aka '_NSRange') to expected argument type 'Range<String.Index>' (aka 'Range<String.CharacterView.Index>')
.
let currentText = textView.text as NSString?
. let updatedText =
줄을로 바꿉니다 let updatedText = currentText?.replacingCharacters(in: range, with: text)
. 마지막으로 if updatedText.isEmpty
줄을로 바꿉니다 if (updatedText?.isEmpty)! {
. 그 트릭을해야합니다!
textView.selectedTextRange
은 func textViewDidChangeSelection(_ textView: UITextView)
무한 루프를 발생 ...
텍스트보기의 문자 수에 대한 변경 사항을 추적하여 자리 표시 자 레이블을 텍스트보기 위에 배치하고 글꼴, 색상을 설정하고 자리 표시 자 가시성을 관리하는 것은 간단하고 안전하며 신뢰할 수 있습니다.
스위프트 3 :
class NotesViewController : UIViewController, UITextViewDelegate {
@IBOutlet var textView : UITextView!
var placeholderLabel : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
placeholderLabel = UILabel()
placeholderLabel.text = "Enter some text..."
placeholderLabel.font = UIFont.italicSystemFont(ofSize: (textView.font?.pointSize)!)
placeholderLabel.sizeToFit()
textView.addSubview(placeholderLabel)
placeholderLabel.frame.origin = CGPoint(x: 5, y: (textView.font?.pointSize)! / 2)
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.isHidden = !textView.text.isEmpty
}
func textViewDidChange(_ textView: UITextView) {
placeholderLabel.isHidden = !textView.text.isEmpty
}
}
스위프트 2 : 동일은 제외 : italicSystemFontOfSize(textView.font.pointSize)
,UIColor.lightGrayColor
KMPlaceholderTextView 라이브러리 를 사용하는 것이 좋습니다 . 사용하기 매우 간단합니다.
빠른:
프로그래밍 방식으로 또는 Interface Builder를 통해 텍스트 뷰를 추가하고 마지막 경우 콘센트를 만듭니다.
@IBOutlet weak var yourTextView: UITextView!
델리게이트 (UITextViewDelegate)를 추가하십시오 :
class ViewController: UIViewController, UITextViewDelegate {
viewDidLoad 메소드에서 다음을 추가하십시오.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
yourTextView.delegate = self
yourTextView.text = "Placeholder text goes right here..."
yourTextView.textColor = UIColor.lightGray
이제 마법 부분을 소개 하고이 기능을 추가하십시오.
func textViewDidBeginEditing(_ textView: UITextView) {
if yourTextView.textColor == UIColor.lightGray {
yourTextView.text = ""
yourTextView.textColor = UIColor.black
}
}
편집이 시작될 때마다 실행되며 color 속성을 사용하여 상태를 알려주는 조건을 확인합니다. 텍스트를 nil
i로 설정 하지 않는 것이 좋습니다. 그 직후 텍스트 색상을 원하는 경우 (이 경우 검은 색)로 설정합니다.
이제이 기능도 추가하십시오.
func textViewDidEndEditing(_ textView: UITextView) {
if yourTextView.text == "" {
yourTextView.text = "Placeholder text ..."
yourTextView.textColor = UIColor.lightGray
}
}
주장하지 말고 비교하지 마십시오 nil
. 나는 이미 그것을 시도했지만 작동하지 않을 것입니다. 그런 다음 값을 플레이스 홀더 스타일로 다시 설정하고 체크인하기위한 조건이므로 색상을 플레이스 홀더 색상으로 다시 설정합니다 textViewDidBeginEditing
.
이 확장명을 사용하면 UITextView에서 자리 표시자를 설정하는 가장 좋은 방법입니다. 그러나 TextView에 대리자를 연결했는지 확인하십시오. 다음과 같이 자리 표시자를 설정할 수 있습니다.
yourTextView.placeholder = "Placeholder"
extension UITextView :UITextViewDelegate
{
/// Resize the placeholder when the UITextView bounds change
override open var bounds: CGRect {
didSet {
self.resizePlaceholder()
}
}
/// The UITextView placeholder text
public var placeholder: String? {
get {
var placeholderText: String?
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderText = placeholderLabel.text
}
return placeholderText
}
set {
if let placeholderLabel = self.viewWithTag(100) as! UILabel? {
placeholderLabel.text = newValue
placeholderLabel.sizeToFit()
} else {
self.addPlaceholder(newValue!)
}
}
}
/// When the UITextView did change, show or hide the label based on if the UITextView is empty or not
///
/// - Parameter textView: The UITextView that got updated
public func textViewDidChange(_ textView: UITextView) {
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderLabel.isHidden = self.text.characters.count > 0
}
}
/// Resize the placeholder UILabel to make sure it's in the same position as the UITextView text
private func resizePlaceholder() {
if let placeholderLabel = self.viewWithTag(100) as! UILabel? {
let labelX = self.textContainer.lineFragmentPadding
let labelY = self.textContainerInset.top - 2
let labelWidth = self.frame.width - (labelX * 2)
let labelHeight = placeholderLabel.frame.height
placeholderLabel.frame = CGRect(x: labelX, y: labelY, width: labelWidth, height: labelHeight)
}
}
/// Adds a placeholder UILabel to this UITextView
private func addPlaceholder(_ placeholderText: String) {
let placeholderLabel = UILabel()
placeholderLabel.text = placeholderText
placeholderLabel.sizeToFit()
placeholderLabel.font = self.font
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.tag = 100
placeholderLabel.isHidden = self.text.characters.count > 0
self.addSubview(placeholderLabel)
self.resizePlaceholder()
self.delegate = self
}
}
아무도 언급하지 않은 것이 놀랍습니다 NSTextStorageDelegate
. UITextViewDelegate
의 메소드는 사용자 상호 작용에 의해서만 트리거되지만 프로그래밍 방식으로는 발생하지 않습니다. 예를 들어 텍스트 뷰의 text
속성을 프로그래밍 방식으로 설정하면 대리자 메서드가 호출되지 않으므로 자리 표시 자의 가시성을 직접 설정해야합니다.
그러나 NSTextStorageDelegate
의 textStorage(_:didProcessEditing:range:changeInLength:)
방법을 사용하면 프로그래밍 방식으로 완료된 경우에도 텍스트 변경 사항에 대한 알림을받습니다. 다음과 같이 지정하십시오.
textView.textStorage.delegate = self
(에서는 UITextView
,이 위양 호텔입니다 nil
그것이 어떤 기본 동작에 영향을주지 않도록, 기본적으로.)
와 결합 UILabel
, 하나는 쉽게 전체 포장 할 수 있습니다 보여줍니다 @clearlight 기술 UITextView
의 placeholder
확장으로 구현.
extension UITextView {
private class PlaceholderLabel: UILabel { }
private var placeholderLabel: PlaceholderLabel {
if let label = subviews.compactMap( { $0 as? PlaceholderLabel }).first {
return label
} else {
let label = PlaceholderLabel(frame: .zero)
label.font = font
addSubview(label)
return label
}
}
@IBInspectable
var placeholder: String {
get {
return subviews.compactMap( { $0 as? PlaceholderLabel }).first?.text ?? ""
}
set {
let placeholderLabel = self.placeholderLabel
placeholderLabel.text = newValue
placeholderLabel.numberOfLines = 0
let width = frame.width - textContainer.lineFragmentPadding * 2
let size = placeholderLabel.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
placeholderLabel.frame.size.height = size.height
placeholderLabel.frame.size.width = width
placeholderLabel.frame.origin = CGPoint(x: textContainer.lineFragmentPadding, y: textContainerInset.top)
textStorage.delegate = self
}
}
}
extension UITextView: NSTextStorageDelegate {
public func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorageEditActions, range editedRange: NSRange, changeInLength delta: Int) {
if editedMask.contains(.editedCharacters) {
placeholderLabel.isHidden = !text.isEmpty
}
}
}
라는 개인 (중첩) 클래스를 사용합니다 PlaceholderLabel
. 전혀 구현되지 않았지만 자리 표시 자 레이블을 식별하는 방법을 제공합니다.이 레이블은 tag
속성을 사용하는 것보다 훨씬 빠릅니다 .
이 방법을 사용하면의 대리인 UITextView
을 다른 사람에게 할당 할 수 있습니다 .
텍스트 뷰의 클래스를 변경할 필요조차 없습니다. 확장명 만 추가하면 UITextView
Interface Builder에서도 프로젝트의 모든 개체에 자리 표시 자 문자열을 할당 할 수 있습니다 .
placeholderColor
명확성 을 위해 속성 구현 을 생략했지만와 비슷한 계산 변수를 사용하여 몇 줄 더 구현할 수 있습니다 placeholder
.
textView.textStorage.delegate = self
이것은 뷰 컨트롤러에서 뷰 컨트롤러를와 바인딩해야합니다 NSTextStorageDelegate
. 정말 필요한가요?
NSTextStorageDelegate
뷰 컨트롤러가 아닌 텍스트 뷰 자체 입니다.
두 가지 텍스트보기를 사용 하여이 작업을 수행했습니다.
일단 사용자가 전경에서 물건을 입력하기 시작하면 배경의 자리 표시자가 사라지고 사용자가 모든 것을 삭제하면 다시 나타납니다. 따라서 한 줄 텍스트 필드의 자리 표시 자처럼 동작합니다.
여기 내가 사용한 코드가 있습니다. descriptionField는 사용자가 입력하는 필드이고 descriptionPlaceholder는 백그라운드에있는 필드입니다.
func textViewDidChange(descriptionField: UITextView) {
if descriptionField.text.isEmpty == false {
descriptionPlaceholder.text = ""
} else {
descriptionPlaceholder.text = descriptionPlaceholderText
}
}
여기에있는 훌륭한 제안 중 일부를 기반으로 다음과 같은 경량의 Interface-Builder 호환 하위 클래스를 구성 할 수있었습니다 UITextView
.
UITextField
.text
속성을 보고 텍스트를 외부 클래스와 완전히 분리 합니다.특히 iOS의 자리 표시 자 색상을 하드 코딩하는 대신 프로그래밍 방식으로 가져올 수있는 방법이 있다면 개선 제안을 환영합니다.
스위프트 v5 :
import UIKit
@IBDesignable class TextViewWithPlaceholder: UITextView {
override var text: String! { // Ensures that the placeholder text is never returned as the field's text
get {
if showingPlaceholder {
return "" // When showing the placeholder, there's no real text to return
} else { return super.text }
}
set { super.text = newValue }
}
@IBInspectable var placeholderText: String = ""
@IBInspectable var placeholderTextColor: UIColor = UIColor(red: 0.78, green: 0.78, blue: 0.80, alpha: 1.0) // Standard iOS placeholder color (#C7C7CD). See /programming/31057746/whats-the-default-color-for-placeholder-text-in-uitextfield
private var showingPlaceholder: Bool = true // Keeps track of whether the field is currently showing a placeholder
override func didMoveToWindow() {
super.didMoveToWindow()
if text.isEmpty {
showPlaceholderText() // Load up the placeholder text when first appearing, but not if coming back to a view where text was already entered
}
}
override func becomeFirstResponder() -> Bool {
// If the current text is the placeholder, remove it
if showingPlaceholder {
text = nil
textColor = nil // Put the text back to the default, unmodified color
showingPlaceholder = false
}
return super.becomeFirstResponder()
}
override func resignFirstResponder() -> Bool {
// If there's no text, put the placeholder back
if text.isEmpty {
showPlaceholderText()
}
return super.resignFirstResponder()
}
private func showPlaceholderText() {
showingPlaceholder = true
textColor = placeholderTextColor
text = placeholderText
}
}
뷰로드의 설정 값
txtVw!.autocorrectionType = UITextAutocorrectionType.No
txtVw!.text = "Write your Placeholder"
txtVw!.textColor = UIColor.lightGrayColor()
func textViewDidBeginEditing(textView: UITextView) {
if (txtVw?.text == "Write your Placeholder")
{
txtVw!.text = nil
txtVw!.textColor = UIColor.blackColor()
}
}
func textViewDidEndEditing(textView: UITextView) {
if txtVw!.text.isEmpty
{
txtVw!.text = "Write your Placeholder"
txtVw!.textColor = UIColor.lightGrayColor()
}
textView.resignFirstResponder()
}
나는 clearlight 의 답변 으로부터 코드를 편리하게 만들려고 노력했다 .
extension UITextView{
func setPlaceholder() {
let placeholderLabel = UILabel()
placeholderLabel.text = "Enter some text..."
placeholderLabel.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
placeholderLabel.sizeToFit()
placeholderLabel.tag = 222
placeholderLabel.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.isHidden = !self.text.isEmpty
self.addSubview(placeholderLabel)
}
func checkPlaceholder() {
let placeholderLabel = self.viewWithTag(222) as! UILabel
placeholderLabel.isHidden = !self.text.isEmpty
}
}
용법
override func viewDidLoad() {
textView.delegate = self
textView.setPlaceholder()
}
func textViewDidChange(_ textView: UITextView) {
textView.checkPlaceholder()
}
하나 더 해결책 (Swift 3) :
import UIKit
protocol PlaceholderTextViewDelegate {
func placeholderTextViewDidChangeText(_ text:String)
func placeholderTextViewDidEndEditing(_ text:String)
}
final class PlaceholderTextView: UITextView {
var notifier:PlaceholderTextViewDelegate?
var placeholder: String? {
didSet {
placeholderLabel?.text = placeholder
}
}
var placeholderColor = UIColor.lightGray
var placeholderFont = UIFont.appMainFontForSize(14.0) {
didSet {
placeholderLabel?.font = placeholderFont
}
}
fileprivate var placeholderLabel: UILabel?
// MARK: - LifeCycle
init() {
super.init(frame: CGRect.zero, textContainer: nil)
awakeFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(PlaceholderTextView.textDidChangeHandler(notification:)), name: .UITextViewTextDidChange, object: nil)
placeholderLabel = UILabel()
placeholderLabel?.textColor = placeholderColor
placeholderLabel?.text = placeholder
placeholderLabel?.textAlignment = .left
placeholderLabel?.numberOfLines = 0
}
override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel?.font = placeholderFont
var height:CGFloat = placeholderFont.lineHeight
if let data = placeholderLabel?.text {
let expectedDefaultWidth:CGFloat = bounds.size.width
let fontSize:CGFloat = placeholderFont.pointSize
let textView = UITextView()
textView.text = data
textView.font = UIFont.appMainFontForSize(fontSize)
let sizeForTextView = textView.sizeThatFits(CGSize(width: expectedDefaultWidth,
height: CGFloat.greatestFiniteMagnitude))
let expectedTextViewHeight = sizeForTextView.height
if expectedTextViewHeight > height {
height = expectedTextViewHeight
}
}
placeholderLabel?.frame = CGRect(x: 5, y: 0, width: bounds.size.width - 16, height: height)
if text.isEmpty {
addSubview(placeholderLabel!)
bringSubview(toFront: placeholderLabel!)
} else {
placeholderLabel?.removeFromSuperview()
}
}
func textDidChangeHandler(notification: Notification) {
layoutSubviews()
}
}
extension PlaceholderTextView : UITextViewDelegate {
// MARK: - UITextViewDelegate
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if(text == "\n") {
textView.resignFirstResponder()
return false
}
return true
}
func textViewDidChange(_ textView: UITextView) {
notifier?.placeholderTextViewDidChangeText(textView.text)
}
func textViewDidEndEditing(_ textView: UITextView) {
notifier?.placeholderTextViewDidEndEditing(textView.text)
}
}
결과
나를 위해 간단하고 빠른 해결책은 다음과 같습니다.
@IBDesignable
class PlaceHolderTextView: UITextView {
@IBInspectable var placeholder: String = "" {
didSet{
updatePlaceHolder()
}
}
@IBInspectable var placeholderColor: UIColor = UIColor.gray {
didSet {
updatePlaceHolder()
}
}
private var originalTextColor = UIColor.darkText
private var originalText: String = ""
private func updatePlaceHolder() {
if self.text == "" || self.text == placeholder {
self.text = placeholder
self.textColor = placeholderColor
if let color = self.textColor {
self.originalTextColor = color
}
self.originalText = ""
} else {
self.textColor = self.originalTextColor
self.originalText = self.text
}
}
override func becomeFirstResponder() -> Bool {
let result = super.becomeFirstResponder()
self.text = self.originalText
self.textColor = self.originalTextColor
return result
}
override func resignFirstResponder() -> Bool {
let result = super.resignFirstResponder()
updatePlaceHolder()
return result
}
}
이 일을 위해 내가 사용하고있는 것이 있습니다.
@IBDesignable class UIPlaceholderTextView: UITextView {
var placeholderLabel: UILabel?
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
sharedInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
sharedInit()
}
override func prepareForInterfaceBuilder() {
sharedInit()
}
func sharedInit() {
refreshPlaceholder()
NotificationCenter.default.addObserver(self, selector: #selector(textChanged), name: UITextView.textDidChangeNotification, object: nil)
}
@IBInspectable var placeholder: String? {
didSet {
refreshPlaceholder()
}
}
@IBInspectable var placeholderColor: UIColor? = .darkGray {
didSet {
refreshPlaceholder()
}
}
@IBInspectable var placeholderFontSize: CGFloat = 14 {
didSet {
refreshPlaceholder()
}
}
func refreshPlaceholder() {
if placeholderLabel == nil {
placeholderLabel = UILabel()
let contentView = self.subviews.first ?? self
contentView.addSubview(placeholderLabel!)
placeholderLabel?.translatesAutoresizingMaskIntoConstraints = false
placeholderLabel?.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: textContainerInset.left + 4).isActive = true
placeholderLabel?.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: textContainerInset.right + 4).isActive = true
placeholderLabel?.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textContainerInset.top).isActive = true
placeholderLabel?.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: textContainerInset.bottom)
}
placeholderLabel?.text = placeholder
placeholderLabel?.textColor = placeholderColor
placeholderLabel?.font = UIFont.systemFont(ofSize: placeholderFontSize)
}
@objc func textChanged() {
if self.placeholder?.isEmpty ?? true {
return
}
UIView.animate(withDuration: 0.25) {
if self.text.isEmpty {
self.placeholderLabel?.alpha = 1.0
} else {
self.placeholderLabel?.alpha = 0.0
}
}
}
override var text: String! {
didSet {
textChanged()
}
}
}
나는 이것과 비슷한 몇 가지 접근법이 있지만 이것의 이점은 다음과 같습니다.
스위프트 3.2
extension EditProfileVC:UITextViewDelegate{
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == UIColor.lightGray {
textView.text = nil
textView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
}
}
}
사용자가 textViewDidBeginEditing 호출을 편집하기 시작한 다음 텍스트 회색의 색상이 사용자가 아무것도 쓰지 않았 음을 의미하는지 확인한 다음 textview nil로 설정하고 사용자 문자 메시지의 색상을 검은 색으로 변경하십시오.
사용자가 textViewDidEndEditing 편집을 호출하고 사용자가 textview에 아무것도 쓰지 않았는지 확인하면 텍스트 "PlaceHolder"와 함께 회색으로 설정된 텍스트
이 문제를 해결하는 내 방법은 다음과 같습니다 ( Swift 4 ).
아이디어는 다른 색상의 자리 표시자를 사용하고 자리 표시 자 크기로 크기를 조정 delegate
하고 모든 UITextView
기능이 예상대로 작동하도록 유지 하는 동안 가능한 가장 간단한 솔루션을 만드는 것 입니다.
import UIKit
class PlaceholderTextView: UITextView {
var placeholderColor: UIColor = .lightGray
var defaultTextColor: UIColor = .black
private var isShowingPlaceholder = false {
didSet {
if isShowingPlaceholder {
text = placeholder
textColor = placeholderColor
} else {
textColor = defaultTextColor
}
}
}
var placeholder: String? {
didSet {
isShowingPlaceholder = !hasText
}
}
@objc private func textViewDidBeginEditing(notification: Notification) {
textColor = defaultTextColor
if isShowingPlaceholder { text = nil }
}
@objc private func textViewDidEndEditing(notification: Notification) {
isShowingPlaceholder = !hasText
}
// MARK: - Construction -
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
NotificationCenter.default.addObserver(self, selector: #selector(textViewDidBeginEditing(notification:)), name: UITextView.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(textViewDidEndEditing(notification:)), name: UITextView.textDidEndEditingNotification, object: nil)
}
// MARK: - Destruction -
deinit { NotificationCenter.default.removeObserver(self) }
}
사람들이 왜이 문제를 지나치게 복잡하게하는지 모르겠습니다 .. 매우 간단하고 간단합니다. 요청 된 기능을 제공하는 UITextView의 서브 클래스입니다.
- (void)customInit
{
self.contentMode = UIViewContentModeRedraw;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil];
}
- (void)textChanged:(NSNotification *)notification
{
if (notification.object == self) {
if(self.textStorage.length != 0 || !self.textStorage.length) {
[self setNeedsDisplay];
}
}
}
#pragma mark - Setters
- (void)setPlaceholderText:(NSString *)placeholderText withFont:(UIFont *)font
{
self.placeholderText = placeholderText;
self.placeholderTextFont = font;
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
[[UIColor lightGrayColor] setFill];
if (self.textStorage.length != 0) {
return;
}
CGRect inset = CGRectInset(rect, 8, 8);//Default rect insets for textView
NSDictionary *attributes = @{NSFontAttributeName: self.placeholderTextFont, NSForegroundColorAttributeName: [UIColor grayColor]};
[self.placeholderText drawInRect:inset withAttributes:attributes];
}`
여러 텍스트보기로 작업하는 경우 솔루션을 사용할 준비가되었습니다.
func textViewShouldBeginEditing(textView: UITextView) -> Bool {
// Set cursor to the beginning if placeholder is set
if textView.textColor == UIColor.lightGrayColor() {
textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
}
return true
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// Remove placeholder
if textView.textColor == UIColor.lightGrayColor() && text.characters.count > 0 {
textView.text = ""
textView.textColor = UIColor.blackColor()
}
if text == "\n" {
textView.resignFirstResponder()
return false
}
return true
}
func textViewDidChange(textView: UITextView) {
// Set placeholder if text is empty
if textView.text.isEmpty {
textView.text = NSLocalizedString("Hint", comment: "hint")
textView.textColor = UIColor.lightGrayColor()
textView.selectedTextRange = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
}
}
func textViewDidChangeSelection(textView: UITextView) {
// Set cursor to the beginning if placeholder is set
let firstPosition = textView.textRangeFromPosition(textView.beginningOfDocument, toPosition: textView.beginningOfDocument)
// Do not change position recursively
if textView.textColor == UIColor.lightGrayColor() && textView.selectedTextRange != firstPosition {
textView.selectedTextRange = firstPosition
}
}
스위프트 3.1
이 확장은 나를 위해 잘 작동했습니다 : https://github.com/devxoul/UITextView-Placeholder
다음은 코드 스 니펫입니다.
포드를 통해 설치하십시오.
pod 'UITextView+Placeholder', '~> 1.2'
수업으로 가져 오기
import UITextView_Placeholder
그리고 placeholder
이미 만든 속성을 추가 하십시오UITextView
textView.placeholder = "Put some detail"
반대로은이 게시물에 대한 모든 대답에 대해, UITextView
않습니다 자리 표시 자 속성이 있습니다. 이해력을 벗어난 이유로 IB에만 노출됩니다.
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/>
</userDefinedRuntimeAttributes>
스토리 보드를 사용하는 경우 정적 자리 표시 자만으로도 속성을 관리자에서 설정하면됩니다.
다음과 같이 코드에서이 속성을 설정할 수도 있습니다.
textView.setValue("My Placeholder", forKeyPath: "placeholder")
날씨가 흐려지면 개인 API를 통해 액세스 할 수 있으며 속성 이 노출됩니다.
이 방법으로 제출하지 않았습니다. 그러나 나는이 방법을 곧 제출 할 것이고 그에 따라이 답변을 업데이트 할 것입니다.
최신 정보:
이 코드를 Apple의 문제없이 여러 릴리스로 제공했습니다.
업데이트 : 이것은 11.2 이전 Xcode에서만 작동합니다
UITextField
NOT UITextView
더 신중하게 질문 / 답변을 참조하십시오.
ios에는 TextView에 자리 표시자를 직접 추가하는 속성이 없으므로 레이블을 추가하고 textView의 변경 사항을 표시하거나 숨길 수 있습니다. SWIFT 2.0 및 textviewdelegate를 구현해야합니다
func textViewDidChange(TextView: UITextView)
{
if txtShortDescription.text == ""
{
self.lblShortDescription.hidden = false
}
else
{
self.lblShortDescription.hidden = true
}
}
Swift-UITextView를 상속받은 클래스를 작성했으며 UILabel을 하위 뷰로 추가하여 자리 표시 자 역할을했습니다.
import UIKit
@IBDesignable
class HintedTextView: UITextView {
@IBInspectable var hintText: String = "hintText" {
didSet{
hintLabel.text = hintText
}
}
private lazy var hintLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFontOfSize(16)
label.textColor = UIColor.lightGrayColor()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
private func setupView() {
translatesAutoresizingMaskIntoConstraints = false
delegate = self
font = UIFont.systemFontOfSize(16)
addSubview(hintLabel)
NSLayoutConstraint.activateConstraints([
hintLabel.leftAnchor.constraintEqualToAnchor(leftAnchor, constant: 4),
hintLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: 8),
hintLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: 4),
hintLabel.heightAnchor.constraintEqualToConstant(30)
])
}
override func layoutSubviews() {
super.layoutSubviews()
setupView()
}
}
나는 @nerdist의 솔루션을 좋아한다. 이를 바탕으로 다음과 같은 확장을 만들었습니다 UITextView
.
import Foundation
import UIKit
extension UITextView
{
private func add(_ placeholder: UILabel) {
for view in self.subviews {
if let lbl = view as? UILabel {
if lbl.text == placeholder.text {
lbl.removeFromSuperview()
}
}
}
self.addSubview(placeholder)
}
func addPlaceholder(_ placeholder: UILabel?) {
if let ph = placeholder {
ph.numberOfLines = 0 // support for multiple lines
ph.font = UIFont.italicSystemFont(ofSize: (self.font?.pointSize)!)
ph.sizeToFit()
self.add(ph)
ph.frame.origin = CGPoint(x: 5, y: (self.font?.pointSize)! / 2)
ph.textColor = UIColor(white: 0, alpha: 0.3)
updateVisibility(ph)
}
}
func updateVisibility(_ placeHolder: UILabel?) {
if let ph = placeHolder {
ph.isHidden = !self.text.isEmpty
}
}
}
예를 들어 ViewController 클래스에서 다음과 같이 사용합니다.
class MyViewController: UIViewController, UITextViewDelegate {
private var notePlaceholder: UILabel!
@IBOutlet weak var txtNote: UITextView!
...
// UIViewController
override func viewDidLoad() {
notePlaceholder = UILabel()
notePlaceholder.text = "title\nsubtitle\nmore..."
txtNote.addPlaceholder(notePlaceholder)
...
}
// UITextViewDelegate
func textViewDidChange(_ textView: UITextView) {
txtNote.updateVisbility(notePlaceholder)
...
}
UITextview에 자리 표시 자!
업데이트 :
코드에서 textview의 텍스트를 변경하는 경우 updateVisibitly 메서드를 호출하여 자리 표시자를 숨기십시오.
txtNote.text = "something in code"
txtNote.updateVisibility(self.notePlaceholder) // hide placeholder if text is not empty.
자리 표시자가 두 번 이상 추가되지 않도록하기 위해 개인 add()
함수가에 추가됩니다 extension
.
swift2.2에서 :
public class CustomTextView: UITextView {
private struct Constants {
static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()
private var placeholderLabelConstraints = [NSLayoutConstraint]()
@IBInspectable public var placeholder: String = "" {
didSet {
placeholderLabel.text = placeholder
}
}
@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
didSet {
placeholderLabel.textColor = placeholderColor
}
}
override public var font: UIFont! {
didSet {
placeholderLabel.font = font
}
}
override public var textAlignment: NSTextAlignment {
didSet {
placeholderLabel.textAlignment = textAlignment
}
}
override public var text: String! {
didSet {
textDidChange()
}
}
override public var attributedText: NSAttributedString! {
didSet {
textDidChange()
}
}
override public var textContainerInset: UIEdgeInsets {
didSet {
updateConstraintsForPlaceholderLabel()
}
}
override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(textDidChange),
name: UITextViewTextDidChangeNotification,
object: nil)
placeholderLabel.font = font
placeholderLabel.textColor = placeholderColor
placeholderLabel.textAlignment = textAlignment
placeholderLabel.text = placeholder
placeholderLabel.numberOfLines = 0
placeholderLabel.backgroundColor = UIColor.clearColor()
placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(placeholderLabel)
updateConstraintsForPlaceholderLabel()
}
private func updateConstraintsForPlaceholderLabel() {
var newConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(\(textContainerInset.top))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints.append(NSLayoutConstraint(
item: placeholderLabel,
attribute: .Width,
relatedBy: .Equal,
toItem: self,
attribute: .Width,
multiplier: 1.0,
constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
))
removeConstraints(placeholderLabelConstraints)
addConstraints(newConstraints)
placeholderLabelConstraints = newConstraints
}
@objc private func textDidChange() {
placeholderLabel.hidden = !text.isEmpty
}
public override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UITextViewTextDidChangeNotification,
object: nil)
}
}
swift3에서 :
import UIKit
CustomTextView 클래스 : UITextView {
private struct Constants {
static let defaultiOSPlaceholderColor = UIColor(red: 0.0, green: 0.0, blue: 0.0980392, alpha: 0.22)
}
private let placeholderLabel: UILabel = UILabel()
private var placeholderLabelConstraints = [NSLayoutConstraint]()
@IBInspectable public var placeholder: String = "" {
didSet {
placeholderLabel.text = placeholder
}
}
@IBInspectable public var placeholderColor: UIColor = CustomTextView.Constants.defaultiOSPlaceholderColor {
didSet {
placeholderLabel.textColor = placeholderColor
}
}
override public var font: UIFont! {
didSet {
placeholderLabel.font = font
}
}
override public var textAlignment: NSTextAlignment {
didSet {
placeholderLabel.textAlignment = textAlignment
}
}
override public var text: String! {
didSet {
textDidChange()
}
}
override public var attributedText: NSAttributedString! {
didSet {
textDidChange()
}
}
override public var textContainerInset: UIEdgeInsets {
didSet {
updateConstraintsForPlaceholderLabel()
}
}
override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
NotificationCenter.default.addObserver(self,
selector: #selector(textDidChange),
name: NSNotification.Name.UITextViewTextDidChange,
object: nil)
placeholderLabel.font = font
placeholderLabel.textColor = placeholderColor
placeholderLabel.textAlignment = textAlignment
placeholderLabel.text = placeholder
placeholderLabel.numberOfLines = 0
placeholderLabel.backgroundColor = UIColor.clear
placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(placeholderLabel)
updateConstraintsForPlaceholderLabel()
}
private func updateConstraintsForPlaceholderLabel() {
var newConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(\(textContainerInset.left + textContainer.lineFragmentPadding))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|-(\(textContainerInset.top))-[placeholder]",
options: [],
metrics: nil,
views: ["placeholder": placeholderLabel])
newConstraints.append(NSLayoutConstraint(
item: placeholderLabel,
attribute: .width,
relatedBy: .equal,
toItem: self,
attribute: .width,
multiplier: 1.0,
constant: -(textContainerInset.left + textContainerInset.right + textContainer.lineFragmentPadding * 2.0)
))
removeConstraints(placeholderLabelConstraints)
addConstraints(newConstraints)
placeholderLabelConstraints = newConstraints
}
@objc private func textDidChange() {
placeholderLabel.isHidden = !text.isEmpty
}
public override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel.preferredMaxLayoutWidth = textContainer.size.width - textContainer.lineFragmentPadding * 2.0
}
deinit {
NotificationCenter.default.removeObserver(self,
name: NSNotification.Name.UITextViewTextDidChange,
object: nil)
}
}
나는 급히 수업을 썼다. 필요할 때마다이 클래스를 가져와야합니다.
textview에 사용할 수있는 자리 표시자가 없습니다. 사용자가 textview에 입력 할 때 레이블을 위에 놓은 다음 숨기거나 사용자가 모든 값을 제거 할 때 기본값으로 설정해야합니다.
func setPlaceholder(){
var placeholderLabel = UILabel()
placeholderLabel.text = "Describe your need..."
placeholderLabel.font = UIFont.init(name: "Lato-Regular", size: 15.0) ?? UIFont.boldSystemFont(ofSize: 14.0)
placeholderLabel.sizeToFit()
descriptionTextView.addSubview(placeholderLabel)
placeholderLabel.frame.origin = CGPoint(x: 5, y: (descriptionTextView.font?.pointSize)! / 2)
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.isHidden = !descriptionTextView.text.isEmpty
}
//Delegate Method.
func textViewDidChange(_ textView: UITextView) {
placeholderLabel.isHidden = !textView.text.isEmpty
}
편집이 완료되면 자리 표시 자 텍스트가 다시 나타나도록 대기열을 전달해야했습니다.
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.text == "Description" {
textView.text = nil
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
DispatchQueue.main.async {
textView.text = "Description"
}
}
}
빠른:
당신의 추가 TextView
@IBOutlet
:
@IBOutlet weak var txtViewMessage: UITextView!
이 viewWillAppear
방법에서 다음을 추가하십시오.
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
txtViewMessage.delegate = self // Give TextViewMessage delegate Method
txtViewMessage.text = "Place Holder Name"
txtViewMessage.textColor = UIColor.lightGray
}
Delegate
Using 확장 (UITextViewDelegate)을 추가하십시오 :
// MARK: - UITextViewDelegate
extension ViewController: UITextViewDelegate
{
func textViewDidBeginEditing(_ textView: UITextView)
{
if !txtViewMessage.text!.isEmpty && txtViewMessage.text! == "Place Holder Name"
{
txtViewMessage.text = ""
txtViewMessage.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView)
{
if txtViewMessage.text.isEmpty
{
txtViewMessage.text = "Place Holder Name"
txtViewMessage.textColor = UIColor.lightGray
}
}
}
우리의 솔루션은 UITextView
text
and textColor
속성을 사용 하지 않아도되므로 문자 카운터를 유지 관리하는 경우 편리합니다.
간단 해:
1) UITextView
스토리 보드에서 마스터와 동일한 속성으로 더미 를 만듭니다 UITextView
. 플레이스 홀더 텍스트를 더미 텍스트에 지정하십시오.
2) 두 개의 상단, 왼쪽 및 오른쪽 가장자리를 정렬 UITextViews.
3) 더미를 마스터 뒤에 놓습니다.
4) textViewDidChange(textView:)
마스터 의 델리게이트 기능을 무시하고 마스터에 0 문자가 있으면 더미를 표시하십시오. 그렇지 않으면 마스터를 보여주십시오.
이것은 둘 다 UITextViews
투명한 배경을 가지고 있다고 가정합니다 . 그렇지 않은 경우 0자가있을 때 더미를 맨 위에 놓고 0이 넘는 문자가있을 때 아래로 밉니다. 또한 커서가 오른쪽을 따르도록 응답기를 교체해야합니다 UITextView
.
스위프트 4, 4.2 및 5
[![@IBOutlet var detailTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
detailTextView.delegate = self
}
extension ContactUsViewController : UITextViewDelegate {
public func textViewDidBeginEditing(_ textView: UITextView) {
if textView.text == "Write your message here..." {
detailTextView.text = ""
detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.86)
}
textView.becomeFirstResponder()
}
public func textViewDidEndEditing(_ textView: UITextView) {
if textView.text == "" {
detailTextView.text = "Write your message here..."
detailTextView.textColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.30)
}
textView.resignFirstResponder()
}
[![}][1]][1]