美文网首页
UITextView的Placeholder

UITextView的Placeholder

作者: Mr__Peng__ | 来源:发表于2018-04-19 23:56 被阅读0次

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

    相关文章

      网友评论

          本文标题:UITextView的Placeholder

          本文链接:https://www.haomeiwen.com/subject/anogkftx.html