UITextView自增高,相似微信输入框的效果
前言
最近在看以前的代码的时候,发现自增高的实现有点复杂。在计算高度的时候有些数值是自己估摸着实现的,反正代码看着很不友好,就想着重构一下。完整测试代码在文章最下方!
那么要实现UITextView输入框有两个要点:
- 占位符
- 自增高
首先我们来看一下UITextView
这个东西,乍一看,它跟UITextFiled
如同是一家人,其实他们的父类都不是同一个。UITextView
是继承自UIScrollView
的,而UITextField
是继承自UIControl
的。
Placeholder
做输入框最基本的就是placeholder
(占位符),当然也有些输入框是没有占位符提醒的,比方微信,我们不论它,我就是要搞个占位符。那么问题来了,UITextView
是没有placeholder
这个属性的。这就是最蛋疼的地方,你一个输入框的类,竟然连placeholder
都没有,就想UITextFiled
没有textFieldDidChange:
这个方法一样??!
好吧,那我们就来手动实现一下placeholder
吧。要想增加一个placeholder
其实有很多方法,其中最常用的方法就是给UITextView
上加一个UILabel
,而后在textViewDidChange:
方法里面来控制他的显示和隐藏。那有没有更方便简洁,看起来又比较牛逼的方法呢?有的!
首先,我们来遍历一下UITextView
这个类里的成员变量,用到的是runtime
里的入门小知识
var count: UInt32 = 0let ivars = class_copyIvarList(UITextView.self, &count)for i in 0..<count { let ivar = ivars![Int(i)]; let name = ivar_getName(ivar); let objcName = String(utf8String: name!) print(objcName as Any);}
下面是打印出来的结果
Optional("_private")Optional("_textStorage")Optional("_textContainer")Optional("_layoutManager")### Optional("_containerView") ###Optional("_inputDelegate")Optional("_tokenizer")Optional("_inputController")Optional("_interactionAssistant")Optional("_textInputTraits")Optional("_autoscroll")Optional("_tvFlags")Optional("_contentSizeUpdateSeqNo")Optional("_scrollTarget")Optional("_scrollPositionDontRecordCount")Optional("_scrollPosition")Optional("_offsetFromScrollPosition")Optional("_linkInteractionItem")Optional("_dataDetectorTypes")Optional("_preferredMaxLayoutWidth")### Optional("_placeholderLabel") ###Optional("_inputAccessoryView")Optional("_linkTextAttributes")Optional("_streamingManager")Optional("_characterStreamingManager")Optional("_siriAnimationStyle")Optional("_siriAlignment")Optional("_siriParameters")Optional("_firstBaselineOffsetFromTop")Optional("_lastBaselineOffsetFromBottom")Optional("_intrinsicSizeCache")Optional("_cuiCatalog")Optional("_beforeFreezingTextContainerInset")Optional("_duringFreezingTextContainerInset")Optional("_beforeFreezingFrameSize")Optional("_unfreezingTextContainerSize")Optional("_animatingPaste")Optional("_frameOfTrailingWhitespace")Optional("_textDragDropSupport")Optional("_topContentPadding")Optional("_bottomContentPadding")Optional("_scrollEndDraggingVelocity")Optional("_adjustsFontForContentSizeCategory")Optional("_clearsOnInsertion")Optional("_pasteDelegate")Optional("_multilineContextWidth")Optional("_textDragOptions")Optional("_textDragDelegate")Optional("_textDropDelegate")Optional("_inputView")Optional("_visualStyle")
是不是一大堆不知所云的东西,其余的不用管,只需看其实用###
标出来的最关键的两个成员变量_placeholderLabel
和_containerView
。先不论_containerView
,先来看_placeholderLabel
,这不就是占位符吗。不过苹果没有把这个暴露出这个属性给开发者使用,那么我们怎样使用者个私有的成员变量呢?当然使用KVC
了!这个时候发现KVC
是个神器了吧!
setValue(placeHolderLabel, forKey: "_placeholderLabel")
这个系统自带的placeholderLabel
和UITextField
的placeholder
一样。你只需自己写个label
赋值给他即可以了,他的显示和消失有系统控制!
那么placeholder
就搞定了,非常简单吧,一个KVC
轻松处理。
自增高
那么如何来实现自增高呢?这个时候大家应该已经想到了上面打印出来的那个被###
出来的两个成员变量之一_containerView
。顾名思义,这个东西就是个内容视图。你用View UI Hierarchy
查看一下就会惊奇的发现,他的frame是根据文字高度变化的,也就是说_containerView
是自增高的!那么问题就处理了,我们用KVC把这个_containerView
取出来。
let containerView = setValue(placeHolderLabel, forKey: "_containerView")
而后再用KVO
监听containerView
// 注册监听containerView.addObserver(self, forKeyPath: "frame", options: .new, context: nil)// 实现监听open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {}
这样我们就完美的实现了UITextView
的自增高,代码又少又简单!
Tips
这里有个关于KVO
的小贴士,苹果在官方文档里已经说明了iOS9.0
以后已经不需要手动removeObserver:
了,除了addObserverForName:object:queue:usingBlock:
方法,由于这个方法在通知中心注册的时候还是强引用的,所以要手动移除。
为什么iOS9.0
以后不需要手动移除Observer
了呢?
由于在iOS9.0
以前,注册Observer
时,通知中心对Observer
做unsafe_unretained
引用,而iOS9.0
以后,通知中心对Observer
实现了weak
引用,这两个引用的区别在与,weak
在对象释放掉之后会置nil
,而unsafe_unretained
在对象释放掉之后会变成野指针,所以需要在对象释放掉之前将Observer
移除,防止野指针通信,造成Crash
。
Discussion
这段代码有一个致命的缺陷是不支持设置contentInset
属性,若是设置了contentInset
文字会上下跳,有兴趣的同学可以在Demo里面测试一下,要是能处理这个问题就再好不过了,谢谢大家啦!
本文Demo仅供交流使用,切勿直接扔进项目里!
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » UITextView自增高,相似微信输入框的效果