博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UITextView实现占位文字的两种方法
阅读量:6671 次
发布时间:2019-06-25

本文共 3890 字,大约阅读时间需要 12 分钟。

在Cocoa Touch框架中有两种系统自带的文本输入控件:UITextFiledUITextView

  • UITextFiled特点
    • 只显示一行文本输入
    • 高度(30)默认不能修改
    • 没有拖拽滚动(父控件是UIscrollView除外)
  • UITextView特点
    • 支持多行输入显示
    • 支持滚动(继承自UIscrollView)
    • 没有占位文字(placeholder)
    • 本质就是一个可调整的多行输入文本框

有时候我们希望给一个多行文本框增加一个占位文字的功能,来提示用户输入的内容。但是这两种都不能满足我们的要求,这样我们可以自定义一个这样的控件,实现我们的需要。

实现思路:

自定义一个类,继承自UITextView,在现有功能的基础上增加一个占位文字的功能

两种实现方法:
1. 实现UITextView内部的- (void)drawRect:(CGRect)rect方法,将占位文字文字画到UITextView控件上

1.1 在.h的头文件中给外界提供一个占位文字的属性

/** *  占位文字 */@property (weak, nonatomic) NSString *placeholder;复制代码

1.2 将占位文字画到矩形框中

/** *  绘制占位文字 */- (void)drawRect:(CGRect)rect {        NSMutableDictionary *attrs = [NSMutableDictionary dictionary];    attrs[NSFontAttributeName] = self.font;    attrs[NSForegroundColorAttributeName] = [UIColor lightGrayColor];    // 在textView的矩形框中绘制文字    [self.placeholder drawInRect:CGRectMake(0, 64, self.frame.size.width, self.frame.size.height) withAttributes:attrs];}复制代码
  • 注:label的font要在初始化时确定,不然程序会奔溃

1.3 采用通知的方式监听键盘文字的改变。文字一旦改变,会发出一个UITextViewTextDidChangeNotification的通知,所以给TextView初始化后就添加一个监听器

- (instancetype)initWithFrame:(CGRect)frame{    if (self = [super initWithFrame:frame]) {        // 添加监听器,监听自己的文字改变通知        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange) name:UITextViewTextDidChangeNotification object:nil];    }        return self;}// 时刻监听文字键盘文字的变化,文字一旦改变便调用setNeedsDisplay方法- (void)textDidChange{    // 该方法会调用drawRect:方法,立即重新绘制占位文字    [self setNeedsDisplay];}复制代码

1.4 添加监听器就要重写dealloc方法,当控件被销毁时,移除监听器

- (void)dealloc{    [[NSNotificationCenter defaultCenter] removeObserver:self];}复制代码

1.5 用户一旦输入了文字,就需要将绘制的占位文字删除掉,所以在drawRect:方法一进来就增加判断

// 如果一旦有输入文字,直接返回,不再绘制占位文字if (self.hasText) return;复制代码

因为drawRect:方法是每次调用会将上次绘制的内容删除掉,重新绘制,所以增加一个这样的判断,当有文字时,再重绘时直接返回,不进行后面的绘制,这样就可以办到有文字输入后,删除占位文字

但其实还有一些问题,控制器中拿到这个textView控件后,可能会随时修改占位文字的字体大小、占位文字的内容,所以避免这些问题,随时响应修改,就需要重写这些属性的setter方法 1.6 重写字体、占位文字等属性的setter方法

// 占位文字的setter方法- (void)setPlaceholder:(NSString *)placeholder{    _placeholder = placeholder;    // 文字一旦改变,立马重写绘制(内部会调drawRect:方法)    [self setNeedsDisplay]; }// 字体属性setter方法- (void)setFont:(UIFont *)font{    [super setFont:font];    [self setNeedsDisplay];}复制代码

这样,这个在系统自带控件基础上自定义的UITextView控件就有占位文字功能了。

2.给自定TextView控件增加一个label属性,用来显示占位文字

这里,相同的部分就不在贴代码,只阐述实现步骤和思路 2.1 在.m文件类扩展增加一个label属性,(写在类扩展中是为了将子控件私有化,不暴漏在外部让被人随意修改属性值)

/** *  占位文字Label */@property (weak, nonatomic) UILabel *phLabel;复制代码

2.2 重写getter方法,采用懒加载,不用关心控件的创建时间,用到时自动加载,同时初始化一些属性

- (UILabel *)phLabel{    if (!_phLabel) {        UILabel *phLabel = [[UILabel alloc] init];         // 文字自动换行        phLabel.numberOfLines = 0;         phLabel.x = 4;        phLabel.y = 7;        [self addSubview:phLabel];        self.phLabel = phLabel;    }        return _phLabel;}复制代码

2.3 给控件添加监听器,代码同上1.3 2.4 重写dealloc方法,移除监听器,同上1.4 2.5 在- (void)textDidChange方法中控制label的显示或隐藏

- (void)textDidChange{    // 有文字就隐藏    self.phLabel.hidden = self.hasText;}复制代码

2.6 在- (void)layoutSubviews方法中动态计算占位文字的label大小

- (void)layoutSubviews{    [super layoutSubviews];    // 确定label的宽度,高度由文字数量自动计算    CGSize size = CGSizeMake(self.width - 2 * self.phLabel.x, MAXFLOAT);   // 根据文字的字体属性、文字的数量动态计算label的尺寸    self.phLabel.size = [self.placeholder boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{
NSFontAttributeName : self.font} context:nil].size;}复制代码
  • 注:label的font要在初始化时确定,不然程序会奔溃

2.7 重写字体、占位文字的setter方法(满足控制器中可能随时修改占位文字的尺寸和大小)

// 占位文字- (void)setPlaceholder:(NSString *)placeholder{    _placeholder = placeholder;    self.phLabel.text = placeholder;        // 更新文字尺寸    [self setNeedsLayout];}// 字体- (void)setFont:(UIFont *)font{    [super setFont:font];    self.phLabel.font = font;    [self setNeedsLayout];}复制代码

setNeedsLayout方法会在控件尺寸变化时调用layoutSubviews重新计算子控件的尺寸和大小

这种方式增加的占位文字有一个优势:

占位文字可以跟随光标一起拖拽上下移动(弹簧效果),但利用drawRect:画上去的占位文字是固定的,没有拖拽效果

控制器在拿到这个控件后,设置占位文字后就可以直接用了。

转载于:https://juejin.im/post/5a332389f265da43294e15cd

你可能感兴趣的文章
Java程序运行超时后退出或进行其他操作的实现
查看>>
赢在起跑点半途就退场,锂电池先行者企业黯然离席
查看>>
手把手教你启用RemoteFX以及Hyper-V GPU卸载
查看>>
《交互式程序设计 第2版》一3.10 更进一步
查看>>
液晶拼接屏的专业术语有哪些
查看>>
微博悄然取消140字限制 面向全体用户
查看>>
OA系统软件怎么选型?
查看>>
英伟达发布Tesla P4&P40两款基于Pascal架构的深度学习芯片
查看>>
《Web应用漏洞侦测与防御:揭秘鲜为人知的攻击手段和防御技术》——1.5 Web Worker...
查看>>
《UNIX网络编程 卷1:套接字联网API(第3版)》——8.10 UDP程序例子小结
查看>>
拯救 Firefox !
查看>>
《人工智能:计算Agent基础》——2.2 Agent系统
查看>>
Firefox 53 Beta 引入两个新 “Compact” 主题
查看>>
英特尔增强 Android 安全 提高自家芯片吸引力
查看>>
《腾讯iOS测试实践》一一1.2 工程效率
查看>>
《Photoshop Lightroom4 经典教程》—第1课1.1节了解Lightroom的工作方式
查看>>
《数据科学:R语言实现》——第2章 数据抽取、转换和加载
查看>>
《深入理解Spark:核心思想与源码分析》——3.7节创建和启动DAGScheduler
查看>>
《ANSYS Workbench有限元分析实例详解(静力学)》——2.5 Windows界面相应操作
查看>>
《R与Hadoop大数据分析实战》一1.7 Hadoop的子项目
查看>>