A kullanan bir uygulama yapıyorum UITextView
. Şimdi Metin Görünümünde, Metin Alanı için ayarlayabileceğinize benzer bir yer tutucu olmasını istiyorum. Swift kullanarak bunu nasıl başardınız?
A kullanan bir uygulama yapıyorum UITextView
. Şimdi Metin Görünümünde, Metin Alanı için ayarlayabileceğinize benzer bir yer tutucu olmasını istiyorum. Swift kullanarak bunu nasıl başardınız?
Yanıtlar:
Swift 4 için güncellendi
UITextView
doğası gereği bir yer tutucu özelliğine sahip olmadığından, UITextViewDelegate
yöntemleri kullanarak programlı olarak bir tane oluşturmanız ve değiştirmeniz gerekir . İstenen davranışa bağlı olarak aşağıdaki # 1 veya # 2 çözümünü kullanmanızı öneririm.
Not: Her iki çözüm UITextViewDelegate
için de sınıfa ekleyin textView.delegate = self
ve metin görünümünün temsilci yöntemlerini kullanacak şekilde ayarlayın .
Çözüm # 1 - Kullanıcı metin görünümünü seçer seçmez yer tutucunun yok olmasını istiyorsanız:
Önce UITextView
, yer tutucu metnini içerecek şekilde ayarlayın ve bir yer tutucu metninin görünümünü taklit etmek için açık gri bir renge ayarlayın UITextField
. Ya viewDidLoad
metin görünümünün oluşturulmasında ya da üzerinde yapın.
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
Daha sonra kullanıcı metin görünümünü düzenlemeye başladığında, metin görünümü bir yer tutucu içeriyorsa (örn. Metin rengi açık gri ise) yer tutucu metni temizleyin ve kullanıcının girişini karşılamak için metin rengini siyaha ayarlayın.
func textViewDidBeginEditing(_ textView: UITextView) {
if textView.textColor == UIColor.lightGray {
textView.text = nil
textView.textColor = UIColor.black
}
}
Ardından, kullanıcı metin görünümünü düzenlemeyi bitirdiğinde ve ilk yanıtlayıcı olarak istifa ettiğinde, metin görünümü boşsa, yer tutucu metni yeniden ekleyerek ve rengini açık gri olarak ayarlayarak yer tutucusunu sıfırlayın.
func textViewDidEndEditing(_ textView: UITextView) {
if textView.text.isEmpty {
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
}
}
Çözüm # 2 - Metin görünümü seçili olsa bile, yer tutucunun metin görünümü boş olduğunda gösterilmesini istiyorsanız:
İlk olarak yer tutucuyu şurada ayarlayın viewDidLoad
:
textView.text = "Placeholder"
textView.textColor = UIColor.lightGray
textView.becomeFirstResponder()
textView.selectedTextRange = textView.textRange(from: textView.beginningOfDocument, to: textView.beginningOfDocument)
(Not: OP, görünüm yüklenir yüklenmez metin görünümünün seçilmesini istediğinden, yukarıdaki görünümde metin görünümü seçimini dahil ettim. İstediğiniz davranış bu değilse ve görünüm yüklendiğinde metin görünümünün seçilmesini istemiyorsanız, Yukarıdaki kod yığınından son iki satırı kaldırın.)
Sonra shouldChangeTextInRange
UITextViewDelegate
yöntemi kullanın, şöyle:
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
}
Ayrıca textViewDidChangeSelection
, kullanıcının yer tutucu görünürken imlecin konumunu değiştirmesini önlemek için de uygulayın . (Not: textViewDidChangeSelection
görünüm yüklenmeden önce çağrılır, bu nedenle yalnızca metin görünürse metin görünümünün rengini kontrol edin):
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
. Bunu yapmazsanız, textViewDidBeginEditing
ve textViewDidEndEditing
işlevleri çalışmaz.
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 =
Satırı şuna dönüştür let updatedText = currentText?.replacingCharacters(in: range, with: text)
. Son olarak, if updatedText.isEmpty
satırı dönüştürün if (updatedText?.isEmpty)! {
. Hile yapmalı!
textView.selectedTextRange
içinden func textViewDidChangeSelection(_ textView: UITextView)
... sonsuz bir döngüye neden olur
Bir yer tutucu etiketi bir metin görünümünün üzerine yerleştirmek, yazı tipini ayarlamak, rengini ayarlamak ve metin görünümünün karakter sayımındaki değişiklikleri izleyerek yer tutucu görünürlüğünü yönetmek basit, güvenli ve güvenilirdir.
Hızlı 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
}
}
Swift 2: Aynen, hariç: italicSystemFontOfSize(textView.font.pointSize)
,UIColor.lightGrayColor
KMPlaceholderTextView kitaplığını kullanmanızı kesinlikle öneririz . Kullanımı çok basit.
Swift:
Metin görünümünüzü programlı olarak veya Arayüz Oluşturucu ile ekleyin, sonuncusu ise çıkışı oluşturun:
@IBOutlet weak var yourTextView: UITextView!
Lütfen temsilci ekleyin (UITextViewDelegate):
class ViewController: UIViewController, UITextViewDelegate {
ViewDidLoad yönteminde aşağıdakileri ekleyin:
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
Şimdi sihirli kısmı tanıtayım, bu işlevi ekleyin:
func textViewDidBeginEditing(_ textView: UITextView) {
if yourTextView.textColor == UIColor.lightGray {
yourTextView.text = ""
yourTextView.textColor = UIColor.black
}
}
Bunun düzenleme başladığında yürütüleceğini unutmayın, orada color özelliğini kullanarak durumu bildirmek için koşulları kontrol edeceğiz. Metnin nil
i olarak ayarlanması önerilmez. Bundan hemen sonra metin rengini istenen, bu durumda siyah olarak ayarladık.
Şimdi bu işlevi de ekleyin:
func textViewDidEndEditing(_ textView: UITextView) {
if yourTextView.text == "" {
yourTextView.text = "Placeholder text ..."
yourTextView.textColor = UIColor.lightGray
}
}
Israr edeyim, karşılaştırmayın nil
, ben zaten denedim ve işe yaramaz. Daha sonra değerleri tekrar yer tutucu stiline ayarlıyoruz ve check-in için bir koşul olduğu için rengi tekrar yer tutucu rengine ayarlıyoruz textViewDidBeginEditing
.
Bu Uzantıyı Kullan, bu, UITextView'da yer tutucu ayarlamanın en iyi yoludur. Ancak, TextView'a delegeler eklediğinizden emin olun. Yer tutucuyu şu şekilde ayarlayabilirsiniz: -
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
}
}
Kimsenin bahsetmediğine şaşırdım NSTextStorageDelegate
. UITextViewDelegate
yöntemleri yalnızca kullanıcı etkileşimi tarafından tetiklenir, ancak programlı olarak tetiklenmez. Örneğin, bir metin görünümünün text
özelliğini programlı olarak ayarladığınızda, temsilci yöntemleri çağrılmayacağından yer tutucunun görünürlüğünü kendiniz ayarlamanız gerekir.
Ancak, NSTextStorageDelegate
's textStorage(_:didProcessEditing:range:changeInLength:)
yöntemi ile, programlı olarak yapılsa bile metinde yapılan herhangi bir değişiklik size bildirilir. Sadece şu şekilde atayın:
textView.textStorage.delegate = self
(İçinde UITextView
, bu temsilci özelliği nil
varsayılan olarak, bu nedenle herhangi bir varsayılan davranışı etkilemez.)
İle birleştirin UILabel
, kolayca bütün sarar gösteriyor @clearlight tekniği UITextView
'nin placeholder
bir uzantısı haline uygulanmasını.
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
}
}
}
Özel (iç içe) sınıfın çağrıldığını unutmayın PlaceholderLabel
. Hiç bir uygulaması yoktur, ancak tag
özelliği kullanmaktan çok daha 'swifty' olan yer tutucu etiketi tanımlamamıza yardımcı olur .
Bu yaklaşımla, delegesini UITextView
başkasına atayabilirsiniz .
Metin görünümlerinizin sınıflarını bile değiştirmeniz gerekmez. Uzantıları eklemeniz yeterlidir UITextView
; hatta Arayüz Oluşturucu'da bile projenizdeki her yere bir yer tutucu dizesi atayabilirsiniz .
placeholderColor
Açıklık nedenleriyle bir mülkün uygulanmasını dışarıda bıraktım , ancak benzer bir hesaplanmış değişkene sahip birkaç satır daha uygulanabilir placeholder
.
textView.textStorage.delegate = self
bu bir görünüm denetleyicisindeki bu görünüm denetleyicisini bağlamamızı gerektirir NSTextStorageDelegate
. Gerçekten gerektirir mi?
NSTextStorageDelegate
görünüm denetleyicisi değil, metin görünümünün kendisidir .
Bunu iki farklı metin görünümü kullanarak yaptım:
Fikir, kullanıcı ön plan görünümünde bir şeyler yazmaya başladığında, arka plandaki yer tutucunun kaybolması (ve kullanıcının her şeyi silmesi durumunda yeniden görünmesi). Dolayısıyla, tek satırlık metin alanı için bir yer tutucu gibi davranır.
İşte bunun için kullandığım kod. DescriptionField öğesinin kullanıcının yazdığı alan ve descriptionPlaceholder öğesinin arka plandaki alan olduğunu unutmayın.
func textViewDidChange(descriptionField: UITextView) {
if descriptionField.text.isEmpty == false {
descriptionPlaceholder.text = ""
} else {
descriptionPlaceholder.text = descriptionPlaceholderText
}
}
Buradaki bazı harika önerilere dayanarak, aşağıdaki hafif, Interface-Builder uyumlu alt sınıfı bir araya getirebildim UITextView
:
UITextField
.text
özelliğine bakarak herhangi bir dış sınıftan tamamen ayrılmasını sağlar .Herhangi bir iyileştirme önerisi, özellikle iOS'un yer tutucu rengini zor kodlamak yerine programlı olarak çekmenin herhangi bir yolu varsa, bekliyoruz.
Swift 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
}
}
Görünüm yükünde SET değeri
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()
}
Ben kod elverişli yapmaya çalıştı Clearlight 'ın cevabı .
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
}
}
kullanım
override func viewDidLoad() {
textView.delegate = self
textView.setPlaceholder()
}
func textViewDidChange(_ textView: UITextView) {
textView.checkPlaceholder()
}
Bir çözüm daha (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)
}
}
sonuç
Benim için çalışan basit ve hızlı bir çözüm:
@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
}
}
İşte bu iş için kullandığım şey.
@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()
}
}
}
Buna benzer çeşitli yaklaşımlar olduğunu biliyorum ama bundan faydaları:
Hızlı 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
}
}
}
İlk olarak kullanıcı textViewDidBeginEditing çağrısını düzenlemeye başladığında ve sonra metin gri renginin kullanıcının herhangi bir şey yazmadığı anlamına geldiğini kontrol ettikten sonra textview nil olarak ayarlayın ve kullanıcı manifatura için rengi siyah olarak değiştirin.
Kullanıcı textViewDidEndEditing düzenlemesini sonlandırdığında çağrı yapılır ve kullanıcının metin görünümünde bir şey yazıp yazmadığını kontrol eder, ardından metin "PlaceHolder" metniyle gri renk olarak ayarlanır
İşte bu sorunu çözme yolum ( Swift 4 ):
Fikir, farklı renkteki yer tutucuların kullanılmasına izin veren, yer tutucu boyutuna göre yeniden boyutlandırılan, bu delegate
arada tüm UITextView
işlevlerin beklendiği gibi çalışmasını sağlamayacak mümkün olan en basit çözümü yapmaktı .
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) }
}
Bu sorunu neden bu kadar karmaşık hale getirenler bilmiyorum .... Oldukça basit ve basit. İşte istenen işlevselliği sağlayan bir UITextView alt sınıfı.
- (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];
}`
Birden fazla metin görünümü ile çalışıyorsanız, bu benim kullanıma hazır çözümüm
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
}
}
Hızlı 3.1
Bu uzantı benim için iyi çalıştı: https://github.com/devxoul/UITextView-Placeholder
İşte bir kod snippet'i:
Kapsülle kurun:
pod 'UITextView+Placeholder', '~> 1.2'
Sınıfınıza aktarın
import UITextView_Placeholder
Ve placeholder
önceden oluşturduğunuza özellik ekleyinUITextView
textView.placeholder = "Put some detail"
Aksine sadece bu yazı her yanıttan, UITextView
does bir yer tutucu özelliği vardır. Anladığımın ötesindeki nedenlerden ötürü, sadece IB'de ortaya çıkar, şöyle:
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="placeholder" value="My Placeholder"/>
</userDefinedRuntimeAttributes>
Öykü tabloları kullanıyorsanız ve statik bir yer tutucu yeterliyse, özelliği denetçide ayarlayın.
Bu özelliği aşağıdaki gibi kodda da ayarlayabilirsiniz:
textView.setValue("My Placeholder", forKeyPath: "placeholder")
Mülkiyet olarak bu hava için Onun bulutlu, özel API aracılığıyla erişilen edilir maruz.
Bu yöntemle göndermeyi denemedim. Ama kısa süre içinde bu şekilde göndereceğim ve bu cevabı buna göre güncelleyeceğim.
GÜNCELLEME:
Apple'dan herhangi bir sorun olmadan birden fazla sürümde bu kodu gönderdim.
GÜNCELLEME: Bu yalnızca 11.2 öncesi Xcode'da çalışır
UITextField
DEĞİL UITextView
daha dikkatli sorular / yanıtlar okuyunuz.
İOS'ta yer tutucuyu doğrudan TextView'a eklemek için böyle bir özellik yoktur, bunun yerine textView'deki değişikliği bir etiket ekleyebilir ve gösterebilir / gizleyebilirsiniz. SWIFT 2.0 ve textviewdelegate'i uyguladığınızdan emin olun
func textViewDidChange(TextView: UITextView)
{
if txtShortDescription.text == ""
{
self.lblShortDescription.hidden = false
}
else
{
self.lblShortDescription.hidden = true
}
}
Swift - UITextView'i devralan bir sınıf yazdım ve yer tutucu olarak hareket etmek için alt görünüm olarak bir UILabel ekledim.
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'in çözümünü seviyorum. Buna dayanarak, bir uzantı oluşturdum 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
}
}
}
Bir ViewController sınıfında, örneğin, ben nasıl kullanırım:
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 üzerinde yer tutucu!
GÜNCELLEME :
Metin görünümünün koddaki metnini değiştirmeniz durumunda, yer tutucuyu gizlemek için updateVisibitly yöntemini çağırmayı unutmayın:
txtNote.text = "something in code"
txtNote.updateVisibility(self.notePlaceholder) // hide placeholder if text is not empty.
Yer tutucunun birden çok kez eklenmesini önlemek için özel bir add()
işlev eklenir extension
.
Swift2.2'de:
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'te:
import UIKit
sınıf 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)
}
}
Hızlı bir şekilde bir sınıf yazdım. Gerektiğinde bu sınıfı içe aktarmanız gerekir.
İtibar nedeniyle yorum ekleyemiyorum. @clearlight yanıtına bir temsilci daha ekleyin.
func textViewDidBeginEditing(_ textView: UITextView) {
cell.placeholderLabel.isHidden = !textView.text.isEmpty
}
İhtiyaç var
çünkü textViewDidChange
ilk defa çağrılmıyor
hayır metin görünümü için kullanılabilir yer tutucu yok. kullanıcı metin görünümüne girdiğinde üstüne etiket koymanız, ardından gizlemeniz veya kullanıcı tüm değerleri kaldırdığında varsayılan değere ayarlamanız gerekir.
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
}
Düzenleme tamamlandıktan sonra yer tutucu metnimin yeniden görünmesi için kuyruk göndermem gerekiyordu.
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"
}
}
}
Swift:
Ekle TextView
@IBOutlet
:
@IBOutlet weak var txtViewMessage: UITextView!
In viewWillAppear
yöntemle aşağıdaki eklerim:
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
txtViewMessage.delegate = self // Give TextViewMessage delegate Method
txtViewMessage.text = "Place Holder Name"
txtViewMessage.textColor = UIColor.lightGray
}
Lütfen Delegate
Kullanma uzantısını ekleyin (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
}
}
}
Bizim çözüm UITextView
text
ve ile mucking önlertextColor
bir karakter sayacını kullanışlı olan özellikleriyle .
Basit:
1) UITextView
Storyboard'da master ile aynı özelliklere sahip bir kukla oluşturunUITextView
. Sahte metne yer tutucu metin atayın.
2) İkisinin üst, sol ve sağ kenarlarını hizalayın UITextViews.
3) Kukla ustanın arkasına yerleştirin.
4) Geçersiz kılın textViewDidChange(textView:)
Master'ın temsilci işlevini master'ın 0 karakteri varsa kukla gösterin. Aksi takdirde, efendiyi gösterin.
Bu, her ikisinin UITextViews
de şeffaf arka planı olduğunu varsayar . Yapmazlarsa, kukla 0 karakter olduğunda üstüne yerleştirin ve> 0 karakter olduğunda altına itin. Ayrıca, imlecin sağa uygun olduğundan emin olmak için yanıtlayanları değiştirmeniz gerekir UITextView
.
Swift 4, 4.2 ve 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]