一个随输入文字宽度变化的自定义UITextField

需求背景:
  • 在textfield的输入内容里加前后加上固定的字符
    "符号A+ 输入内容+ 符号B"

最初的想法是直接在相应的回调中进行处理。
但这样会涉及取值,以及一些复杂情况的处理,比如粘贴,插入等情况的处理。放弃。
然后想着弄三个元素 label+textfield+label的形式。既能方便取值,各种情况也不需要处理,不用关心符号。

接着快速写了测试项目,masonry加了约束。xcode9跑iOS11模拟器,无错。

直接放进项目,继续模拟器运行,完美。然后在我提交代码后的第二天,收到了bug反馈。

说输入的文字宽度没变化。产生挤压,在textfield失去焦点的时候才会正常显示。

猜想:

  1. 是不是约束做的有问题,hugging优先级没弄好?
  2. 是不是需要在输入的时候重新布局或渲染视图?

经过反复调试优先级和验证,约束无错。。。
尝试调用setNeedsLayout / LayoutIfNeeded等方法,无效。

  1. 是不是uitextfield相关的属性有哪些地方没有考虑到?

把textfield相关的官方文档看一遍。
因为要解决这个问题,其实也就是实现另外一个效果:在输入的时候把textfield的宽度变成输入内容等宽。也就涉及到size相关的处理。
第一反应:那就在相应的回调里面,通过计算文字的宽度,改变约束去强制改变textfield的宽度。但强迫症觉得这个方法太恶心,肯定有别的好方法。

面向stackoverflow:

google关键字:textfield changing width when input ios

https://stackoverflow.com/questions/18236661/resize-a-uitextfield-while-typing-by-using-autolayout
https://stackoverflow.com/questions/41436716/how-to-increase-width-of-textfield-according-to-typed-text

这两个提问和我的需求几乎一致,楼下的解决办法都有提到同一个东东:intrinsicContentSize

跟着方法撸一次

  1. subclass of UITextField
  2. override intrinsicContentSize
- (CGSize)intrinsicContentSize {
    return self.isEditing ? [super.text sizeWithAttributes:self.typingAttributes] : [super intrinsicContentSize];
}
  1. handle event for 'UIControlEventEditingChanged'
//UIControlEventEditingChanged
- (IBAction)changedEvent:(UITextField *)sender {
    [sender invalidateIntrinsicContentSize];
}

跑跑,真的可以。but, why?

在invalidateIntrinsicContentSize方法看到相关解释。

call this when something changes that affects the intrinsicContentSize.  Otherwise UIKit  won't notice that it changed.
如果有什么鬼东东影响了它的固有尺寸的时候,就调用这个方法,不然 uikit 根本不知道他产生了变化。

在intrinsicContentSize方法看到相关解释

/* Override this method to tell the layout system that there is something it doesn't natively understand in this view, and this is how large it intrinsically is.  A typical example would be a single line text field.  The layout system does not understand text - it must just be told that there's something in the view, and that that something will take a certain amount of space if not clipped.  
 
 In response, UIKit will set up constraints that specify (1) that the opaque content should not be compressed or clipped, (2) that the view prefers to hug tightly to its content. 
 
 A user of a view may need to specify the priority of these constraints.  For example, by default, a push button 
 -strongly wants to hug its content in the vertical direction (buttons really ought to be their natural height)
 -weakly hugs its content horizontally (extra side padding between the title and the edge of the bezel is acceptable)
 -strongly resists compressing or clipping content in both directions. 
 
 However, you might have a case where you'd prefer to show all the available buttons with truncated text rather than losing some of the buttons. The truncation might only happen in portrait orientation but not in landscape, for example. In that case you'd want to setContentCompressionResistancePriority:forAxis: to (say) UILayoutPriorityDefaultLow for the horizontal axis.
 
 The default 'strong' and 'weak' priorities referred to above are UILayoutPriorityDefaultHigh and UILayoutPriorityDefaultLow.  
 
 Note that not all views have an intrinsicContentSize.  UIView's default implementation is to return (UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric).  The _intrinsic_ content size is concerned only with data that is in the view itself, not in other views. Remember that you can also set constant width or height constraints on any view, and you don't need to override instrinsicContentSize if these dimensions won't be changing with changing view content.

这么多就不翻译了。。自己看吧。不难。大致意思就是重写这个intrincsize方法告诉系统这个视图有多大,也就是你自己定义大小,还有一些约束什么的。
 */ 

也就是说,重写了之后,都会根据它的typingAttributes计算相应的尺寸,然后在回调里面手动触发这个计算,每输入一次就计算一次尺寸。这样textfield的宽度就变成了文字的宽度了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容