UITextView的Placeholder
UITextView 没有placeholder 妹的办法,只好自己实现,Swift 版本主要通过继承UIView,在UIView上添加UITextView 和 一个UILabel实现placeholder,详情看代码,OC实现也差不多。
OC版本使用Runtime 运行时属性添加一个placeholder,和展示placeholder的UILabel
工作上用到的主要Swift 版本,稍微完善一些,Xib中所见即所得已实现,关键字类@IBDesignable 属性 @IBInspectable ,OC高逼格版用可以,不够完善
1. Swift 版本
importFoundation
import UIKit
@IBDesignable class PSTextView: UIView,UITextViewDelegate {
private var ps_placeholder =""
private var ps_maxLength :Int=0
private var ps_isShowNum :Bool=false
private var ps_borderWidth :CGFloat=1
private var ps_borderColor :UIColor=UIColor.groupTableViewBackground
private var ps_cornerRadius :CGFloat=5
private var ps_font :UIFont=UIFont.systemFont(ofSize:14.0)
private var ps_textColor :UIColor=UIColor.black
private var ps_placeholderColor :UIColor=UIColor.lightGray
private var ps_text :String=""
private let numFont :UIFont=UIFont.systemFont(ofSize:10)
private let numHeight :CGFloat=12.0
private let numColor :UIColor =UIColor.gray
private var backgroundView :UIView?// 背景图
private var textView :UITextView?// textView
private var placeholderLb :UILabel?// placeholder label
private var numberLb :UILabel?// 计数器label
override init(frame:CGRect) {// 类使用了@IBDesignable 初始化 --自定义属性的set方法-->draw(_ rect: CGRect),不再执行init(frame: CGRect)
super.init(frame: frame)
}
required init?(coder aDecoder:NSCoder) {
super.init(coder: aDecoder)
// draw(bounds)
}
override func draw(_rect:CGRect) {
load() // 初始化
}
// 添加 UITextView
private func load() {
layer.cornerRadius = ps_cornerRadius
layer.borderWidth = ps_borderWidth
layer.borderColor = ps_borderColor.cgColor
ps_initView()
ps_textViewChange() // xib 中更改属性要走这里
ps_setNumberHidden(hidden: ps_isShowNum) // 设置是否展示最大计数
}
}
//MARK: ============= setter and getter
extension PSTextView {
// 装 系列View 的容器
private func ps_initView() {
textView = UITextView.init(frame:CGRect.init(x:0, y:0, width:self.bounds.width, height:self.bounds.height))
textView?.font = ps_font
textView?.delegate=self
textView?.textColor = ps_textColor
textView?.returnKeyType= .done
textView?.backgroundColor = .clear
textView?.text=text
placeholderLb=UILabel.init()
placeholderLb?.textColor = ps_placeholderColor
placeholderLb?.numberOfLines = 0
placeholderLb?.font = ps_font
placeholderLb?.text = ps_placeholder
numberLb = UILabel.init(frame:CGRect.init(x:0, y: (textView?.bounds.height)! -numHeight, width: (textView?.bounds.width)!, height:numHeight))
numberLb?.font = numFont
numberLb?.textColor = numColor
numberLb?.text = "0/\(ps_maxLength)"
numberLb?.textAlignment= .right
numberLb?.isHidden=true
backgroundView=UIView.init(frame:self.bounds)
backgroundView?.addSubview(placeholderLb!)
backgroundView?.addSubview(textView!)
backgroundView?.addSubview(numberLb!)
addSubview(backgroundView!)
// 关闭 autoresizing
// 自动布局 本来想设置和textView,一样大的 但是placeholder 的text 显示就不正确了,so 使用自动布局 效果还是很不错滴😆
placeholderLb?.translatesAutoresizingMaskIntoConstraints = false
lettextInset =textView?.textContainerInset
let linePadding = textView?.textContainer.lineFragmentPadding
letx = linePadding! + (textInset?.left)!
lety = textInset?.top
let left :NSLayoutConstraint=NSLayoutConstraint.init(item:placeholderLb!, attribute:NSLayoutAttribute.left, relatedBy:NSLayoutRelation.equal, toItem:backgroundView!, attribute:NSLayoutAttribute.left, multiplier:1.0, constant: x)
let top :NSLayoutConstraint=NSLayoutConstraint.init(item:placeholderLb!, attribute:NSLayoutAttribute.top, relatedBy:NSLayoutRelation.equal, toItem:backgroundView!, attribute:NSLayoutAttribute.top, multiplier:1.0, constant: y!)
let right :NSLayoutConstraint=NSLayoutConstraint.init(item:placeholderLb!, attribute:NSLayoutAttribute.right, relatedBy:NSLayoutRelation.equal, toItem:backgroundView!, attribute:NSLayoutAttribute.right, multiplier:1.0, constant: -textInset!.right)
placeholderLb?.superview!.addConstraint(left)
placeholderLb?.superview!.addConstraint(right)
placeholderLb?.superview!.addConstraint(top)
}
/**
* 占位字符串
*/
@IBInspectable var placeholder:String{
get{
return ps_placeholder
}
set{
ps_placeholder= newValue
placeholderLb?.text = ps_placeholder
}
}
/**
* 最多输入多少个字符串
*/
@IBInspectable var maxLength:Int{
get{
return ps_maxLength
}
set{
ps_maxLength= newValue
}
}
/**
* 是否展示数字限制label
*/
@IBInspectable var isShowNum:Bool{
get{
returnps_isShowNum
}set{
ps_isShowNum= newValue
ps_setNumberHidden(hidden: newValue)
}
}
/**
* 边界宽度 默认是1
*/
@IBInspectable varborderWidth:CGFloat{
get{
return ps_borderWidth
}
set{
ps_borderWidth= newValue
layer.borderWidth= newValue
}
}
/**
* 边界线颜色 默认UIColor.groupTableViewBackground
*/
@IBInspectablevarborderColor:UIColor{
get{
return ps_borderColor
}
set{
ps_borderColor= newValue
layer.borderColor= newValue.cgColor
}
}
/**
* 圆角 默认5
*/
@IBInspectable var cornerRadius:CGFloat{
get{
return ps_cornerRadius
}
set{
ps_cornerRadius= newValue
layer.cornerRadius= newValue
}
}
/**
* 字体 默认 系统字体 14号
*/
@IBInspectable var font: UIFont {
get{
returnps_font
}
set{
ps_font= newValue
placeholderLb?.font = ps_font
textView?.font=ps_font
}
}
/**
* text View 颜色 默认 黑色
*/
@IBInspectable var textColor:UIColor{
get{
returnps_textColor
}
set{
ps_textColor= newValue
textView?.textColor = ps_textColor
}
}
/**
* placeholder 颜色
*/
@IBInspectable var placeholderColor:UIColor{
get{
return ps_placeholderColor
}
set{
ps_placeholderColor= newValue
placeholderLb?.textColor= newValue
}
}
/**
* 设置 text
*/
@IBInspectable var text : String {
get{
returnps_text
}set{
textView?.text= newValue
ps_text= newValue
ps_textViewChange()
}
}
}
//MARK: ============= textView Delegate
extension PSTextView {
private func ps_setNumberHidden(hidden :Bool) {
if hidden {
numberLb?.isHidden=false
vartvframe =textView?.frame
tvframe?.size.height-=numHeight
textView?.frame= tvframe!
}else{
numberLb?.isHidden=true
vartvframe =textView?.frame
tvframe?.size.height-=self.frame.height
textView?.frame= tvframe!
}
}
// textView text 改变
private func ps_textViewChange() {
numberLb?.text = "\((textView?.text.count)!)/\(ps_maxLength)"
placeholderLb?.isHidden= ((textView?.text.count)! >0)
}
func text ViewDidChange(_textView:UITextView) {
ps_textViewChange()
ps_text= textView.text
}
func textView(_textView:UITextView, shouldChangeTextIn range:NSRange, replacementText text:String) ->Bool{
if text =="\n"{
ps_resignFirstResponder()
return false
}else{
}
if ps_maxLength==0{
return true
}
let length = textView.text.count- range.length+ text.count
return length <=ps_maxLength
}
/**
* 失去第一响应
*/
func ps_resignFirstResponder() {
textView?.resignFirstResponder()
}
/**
* 成为第一响应者
*/
func ps_becomeFirstResponder() {
textView?.becomeFirstResponder()
}
}
2. OC 高逼格的版本,属性暂时就想了这么多
@interface UITextView (PSPlaceholder)
/**
* UITextView+placeholder
*/
@property(nonatomic,copy)NSString*ps_placeHolder;
/**
* placeHolder颜色
*/
@property(nonatomic,strong)UIColor*ps_placeHolderColor;
@end
.m 文件
//
// UITextView+PSPlaceholder.m
// hehe
// Created by Peng on 2018/4/19.
// Copyright © 2018年 PengShuai. All rights reserved.
//
#import "UITextView+PSPlaceholder.h"
#import
static char ps_placeholderKey;
static char ps_placeholderLbKey; // property keyword
@interface UITextView()
@property (nonatomic, readonly) UILabel *placeholderLabel;
@end
@implementation UITextView (PSPlaceholder)
+ (void)load {
[superload];
// exchange layout Subviews 设置placeholderLb 的frame
method_exchangeImplementations(class_getInstanceMethod(self.class, NSSelectorFromString(@"layoutSubviews")), class_getInstanceMethod(self.class, @selector(ps_layoutSubviews)));
// exchange dealloc 方法 移除通知
method_exchangeImplementations(class_getInstanceMethod(self.class, NSSelectorFromString(@"dealloc")),class_getInstanceMethod(self.class,@selector(ps_dealloc)));
// exchange setText 方法
method_exchangeImplementations(class_getInstanceMethod(self.class, NSSelectorFromString(@"setText:")),class_getInstanceMethod(self.class,@selector(ps_setText:)));
}
// 设置placeholderLabel frame
- (void) ps_layoutSubviews {
if (self.ps_placeHolder) {
UIEdgeInsets textContainerInset =self.textContainerInset;
CGFloat lineFragmentPadding = self.textContainer.lineFragmentPadding;
CGFloatx = lineFragmentPadding + textContainerInset.left+self.layer.borderWidth;
CGFloaty = textContainerInset.top+self.layer.borderWidth;
CGFloatwidth =CGRectGetWidth(self.bounds) - x - textContainerInset.right-2*self.layer.borderWidth;
CGFloatheight = [self.placeholderLabel sizeThatFits:CGSizeMake(width,0)].height;
self.placeholderLabel.frame=CGRectMake(x, y, width, height);
}
[self ps_layoutSubviews];
}
// 移除通知
- (void) ps_dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self ps_dealloc];
}
// 设置 text
- (void) ps_setText:(NSString*) text {
[self ps_setText:text];
if (self.ps_placeHolder) {
[self ps_updatePlaceHolder];
}
}
#pragma mark =========== get and setter
- (UILabel*)placeholderLabel {
UILabel*placeholderLb =objc_getAssociatedObject(self, &ps_placeholderLbKey);
if(!placeholderLb) {
placeholderLb = [[UILabelalloc]init];
placeholderLb.numberOfLines=0;
placeholderLb.textColor= [UIColor lightGrayColor];
objc_setAssociatedObject(self, &ps_placeholderLbKey, placeholderLb, OBJC_ASSOCIATION_RETAIN);
[[NSNotificationCenterdefaultCenter] addObserver:selfselector:@selector(ps_updatePlaceHolder) name:UITextViewTextDidChangeNotification object:self];
}
returnplaceholderLb;
}
- (NSString*)ps_placeHolder {
return objc_getAssociatedObject(self, &ps_placeholderKey);
}
- (void)setPs_placeHolder:(NSString*)ps_placeHolder {
objc_setAssociatedObject(self, &ps_placeholderKey, ps_placeHolder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self ps_updatePlaceHolder];
}
- (UIColor*)ps_placeHolderColor {
return self.placeholderLabel.textColor;
}
- (void)setPs_placeHolderColor:(UIColor*)ps_placeHolderColor {
self.placeholderLabel.textColor= ps_placeHolderColor;
}
#pragma mark - update
- (void)ps_updatePlaceHolder{
if(self.text.length) {
[self.placeholderLabel removeFromSuperview];
return;
}
self.placeholderLabel.font = self.font?self.font:self.ps_getDefaultFont;
self.placeholderLabel.textAlignment = self.textAlignment;
self.placeholderLabel.text = self.ps_placeHolder;
[self insertSubview:self.placeholderLabel atIndex:0];
}
// 获取默认字体
- (UIFont*) ps_getDefaultFont{
static UIFont*font =nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
UITextView*textview = [[UITextViewalloc]init];
textview.text=@" ";
font = textview.font;
});
returnfont;
}
@end
Swift 高逼格版本那个高手会,教一下子呗 QQ 2934525789 微信 18258182915 也可以进QQ群 769718001 一起交流一下iOS开发