You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为TableView Cell中TextField的字号变化添加动画?

问题描述

我有一个包含Label和TextField的TableView Cell。在Storyboard中,TextField的宽度约束设为150,文本使用System Bold 30号字体,开启了「Adjust to fit」,最小字号设为10。

我通过以下代码在TextField开始/结束编辑时,动画调整其宽度约束:

func textFieldDidBeginEditing(_ textField: UITextField) {
    UIView.animate(withDuration: 1) { [self] in
        textFieldWidth.constant = 300
        self.layoutIfNeeded()
    }
}

func textFieldDidEndEditing(_ textField: UITextField) {
    UIView.animate(withDuration: 1) { [self] in
        textFieldWidth.constant = 150
        self.layoutIfNeeded()
    }
}

问题:TextField的字号会直接跳变为30号,没有动画效果;恢复宽度时也是瞬间变化。我试过UIView.transition、带scaleX/scaleY的transform等方法,但效果都不好——比如仅用scaleX缩放会导致文本变形,我需要保持文本宽高比。

期望效果:字号变化(从小号到30号)能和TextField宽度变化同步动画,动画方向从尾部向左。如果无法通过TextField实现,是否有诸如用「假Label」之类的替代方案实现平滑的字号变化?


解决方案

方案一:手动绑定宽度与字号的动画关系

TextField的「Adjust to fit」是系统自动计算字号,不会触发动画,因此需要手动控制字号随宽度的变化比例:

  1. 关闭TextField的「Adjust to fit」,初始字号设为10(对应宽度150时的最小字号)。
  2. 在动画闭包中,根据当前宽度的比例实时计算字号,同步更新TextField的font属性:
func textFieldDidBeginEditing(_ textField: UITextField) {
    let startWidth = 150.0
    let targetWidth = 300.0
    let startFontSize = 10.0
    let targetFontSize = 30.0
    
    UIView.animate(withDuration: 1.0) {
        let widthProgress = (self.textFieldWidth.constant - startWidth) / (targetWidth - startWidth)
        let currentFontSize = startFontSize + (targetFontSize - startFontSize) * widthProgress
        textField.font = .systemFont(ofSize: currentFontSize, weight: .bold)
        
        self.textFieldWidth.constant = targetWidth
        self.layoutIfNeeded()
    }
}

func textFieldDidEndEditing(_ textField: UITextField) {
    let startWidth = 300.0
    let targetWidth = 150.0
    let startFontSize = 30.0
    let targetFontSize = 10.0
    
    UIView.animate(withDuration: 1.0) {
        let widthProgress = (startWidth - self.textFieldWidth.constant) / (startWidth - targetWidth)
        let currentFontSize = startFontSize - (startFontSize - targetFontSize) * widthProgress
        textField.font = .systemFont(ofSize: currentFontSize, weight: .bold)
        
        self.textFieldWidth.constant = targetWidth
        self.layoutIfNeeded()
    }
}

方案二:用Label模拟TextField动画(推荐)

如果TextField自带特性难以满足需求,可以用「展示Label+透明输入TextField」的组合实现完全可控的动画:

  1. 在Cell中添加两个控件:
    • displayLabel:负责展示带动画的文本,开启「Adjust to fit」,最小字号10,初始宽度150,字体为30号Bold,对齐方式设为右对齐(实现从尾部向左的动画方向)。
    • inputTextField:透明背景、无边框,覆盖在displayLabel上方,仅负责接收用户输入。
  2. 动画逻辑:
// 编辑开始时的动画
func textFieldDidBeginEditing(_ textField: UITextField) {
    UIView.animate(withDuration: 1.0) {
        self.displayLabelWidth.constant = 300
        // 根据宽度比例计算字号,从10平滑过渡到30
        let widthRatio = self.displayLabelWidth.constant / 150.0
        let fontSize = 10 + (30 - 10) * (widthRatio - 1)
        self.displayLabel.font = .systemFont(ofSize: fontSize, weight: .bold)
        
        self.inputTextFieldWidth.constant = 300
        self.layoutIfNeeded()
    }
}

// 编辑结束时的动画
func textFieldDidEndEditing(_ textField: UITextField) {
    // 同步输入文本到展示Label
    self.displayLabel.text = textField.text
    
    UIView.animate(withDuration: 1.0) {
        self.displayLabelWidth.constant = 150
        let widthRatio = self.displayLabelWidth.constant / 300.0
        let fontSize = 30 - (30 - 10) * (1 - widthRatio)
        self.displayLabel.font = .systemFont(ofSize: fontSize, weight: .bold)
        
        self.inputTextFieldWidth.constant = 150
        self.layoutIfNeeded()
    }
}

这种方式完全由开发者控制字号和宽度的动画节奏,不会出现系统自动调整导致的跳变,同时保持输入功能正常。

补充优化

  • 若要强化「从尾部向左」的动画方向,确保Label和TextField的文本对齐方式为右对齐,动画时宽度从右侧扩展,文本自然向左展开。
  • 使用UIViewPropertyAnimator替代普通UIView.animate,可以添加弹簧效果、中途暂停/恢复动画等更精细的控制。

内容的提问来源于stack exchange,提问作者artexhibit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:22:53