UITextView的Placeholder

2018-04-19  本文已影响0人  Mr__Peng__

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开发

上一篇下一篇

猜你喜欢

热点阅读