iOS 打字机效果与光标追随

前言

在最近的开发中需要接入一个 AI 模块,UI 上有类似于 chatGPT App 的一些交互体验设计。后端的接口也与 OpenAI 一样多次返回。所以需要写一个打字机的效果,并且有一个移动光标不断跟随文字的显示。简单写了个 demo 模拟一下后端返回,实现这个小需求。

项目地址:TypeFlowView on GitHub

在这里插入图片描述

思路

实现主要包含以下几点:

  1. 定时器:为了实现文字的逐个显示,我们需要一个定时器来控制显示的节奏。
  2. 光标:我们将创建一个自定义视图来模拟光标,并使其位置随文本输入而更新。
  3. 动画:为了使效果更加生动,为光标添加一些简单的动画效果。

主要代码

1. 随机拼文本,模拟后端不断返回

    //appends a random portion of the remaining text and updates the text view and cursor accordingly
    private func appendText() {
        guard let curNews = curNews, curIdx < curNews.count else {
            finishAnimation()
            return
        }

        let remainingLength = curNews.count - curIdx
        let maxReadLength = min(5, remainingLength)
        let read = Int.random(in: 1...maxReadLength)
        let startIndex = curNews.index(curNews.startIndex, offsetBy: curIdx)
        let endIndex = curNews.index(startIndex, offsetBy: read)
        let substring = String(curNews[startIndex..<endIndex])

        textView.text += substring
        updateTextViewHeight()
        updateCursorPosition()
        curIdx += read
    }

2. 使用 CADisplayLink

    private func setupDisplayLink() {
        displayLink = CADisplayLink(target: self, selector: #selector(update))
        displayLink?.preferredFramesPerSecond = Int(1/updateInterval)
        displayLink?.add(to: .main, forMode: .common)
    }

    @objc private func update(displayLink: CADisplayLink) {
        guard lastUpdateTime == 0 || displayLink.timestamp - lastUpdateTime >= updateInterval else {
            return
        }
        lastUpdateTime = displayLink.timestamp
        appendText()
    }

使用 CADisplayLink 而不是 Timer 来控制文本的显示。CADisplayLink 与屏幕刷新率同步,可以提供更流畅的动画效果。

3. 更新光标位置

    private func updateCursorPosition() {
        guard let selectedRange = textView.selectedTextRange else { return }
        let cursorRect = textView.caretRect(for: selectedRange.end)
        
         UIView.animate(withDuration: 0.1, animations: {
             self.cursorView.alpha = 0.2
             self.cursorView.frame = CGRect(x: Int(cursorRect.origin.x + self.textView.frame.origin.x), y: Int(cursorRect.origin.y + self.textView.frame.origin.y) + 4, width: 15, height: 15)
         }) { _ in
             UIView.animate(withDuration: 0.05) {
                 self.cursorView.alpha = 1
             }
         }
    }

尾声

还可以做的:

  • 添加打字声音效果
  • 支持富文本,允许不同样式的文字
  • 优化内存使用,特别是对于非常长的文本

随手写的 demo,考虑的可能不太周全,性能上也没有追求多好。完整代码 TypeFlowView on GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值