douyin-ios-swift 表情系统源码解析:如何用 NSTextAttachment 实现抖音式表情编辑(完整指南)

发布时间:2026/8/23 10:12:38

douyin-ios-swift 表情系统源码解析:如何用 NSTextAttachment 实现抖音式表情编辑(完整指南)
douyin-ios-swift 表情系统源码解析如何用 NSTextAttachment 实现抖音式表情编辑完整指南【免费下载链接】douyin-ios-swift抖音 iOS Swift版项目地址: https://gitcode.com/gh_mirrors/do/douyin-ios-swiftdouyin-ios-swift 是一款用 Swift 编写的高仿抖音 iOS 客户端其 IM 群聊模块中用NSTextAttachment实现了完整的抖音式表情编辑能力在输入框里像输入文字一样插入表情图片、点击删除键整块删掉表情、发送时自动转回[文本]形式存储与传输。本文带你读懂这套表情系统的源码结构与核心实现。表情系统整体结构4个核心文件分工整个表情系统围绕编辑和展示两条链路展开涉及以下模块文件职责EmotionHelper.swift核心工具类文本⇄表情双向转换NSTextAttachmentEmotion.swift给附件附加表情键名EmotionSelector.swift底部表情选择器面板ChatTextView.swift聊天输入框插入/删除表情入口数据方面则依赖 emotion.json表情键值映射表和 Emoticons.bundle 里 100 多张2x/3x表情图片资源。NSTextAttachment 实现原理表情为什么算一个字符核心思想非常巧妙一个表情在文本中只占 1 个字符的位置但渲染时是一张图片。创建一个NSTextAttachment附件把表情图片赋给image属性用NSAttributedString(attachment:)把它包装成长度为 1 的富文本替换掉原占位文本插入UITextView。因此在表情上按删除键时系统会把它当作一个普通字符整体删除这正是整块删除表情效果的关键 。附件的显示区域由bounds决定EmotionHelper.swift 中这样设置让图片高度对齐一行文字attachment.bounds CGRect(x: 0, y: EmotionFont.descender, width: EmotionFont.lineHeight, height: EmotionFont.lineHeight / (image.size.width / image.size.height))表情数据是如何组织的emotion.json 包含两个部分dictkiss → [飞吻]的映射字典key 是 Emoticons.bundle 中的图片文件名不含后缀value 是表情对应的方括号文本array二维数组描述选择器每一页排布的表情文件名供翻页展示。EmotionHelper.swift 通过String.readJson2DicWithFileName定义于 String.swift静态加载这两份数据并提供emotionKeyFromValue/emotionValueFromKey两个方法做 key⇄value 互查。文本⇄表情双向转换的核心代码发送前图片表情转回文本用户在输入框插入的是图片附件但消息要发给服务端必须先转成纯文本。emotionToString遍历富文本中所有attachment属性把每个附件替换回[文本]static func emotionToString(str: NSMutableAttributedString) - NSAttributedString { str.enumerateAttribute(.attachment, in: NSRange(location: 0, length: str.length), options: .longestEffectiveRangeNotRequired) { value, range, stop in if let attachment value as? NSTextAttachment, let key attachment.emotionKey { str.replaceCharacters(in: range, with: EmotionHelper.emotionValueFromKey(key: key)) } } return str }这里有个小细节附件上的emotionKey是通过关联对象Associated Object扩展NSTextAttachment加上的见 NSTextAttachmentEmotion.swift——因为原生NSTextAttachment无法直接添加属性extension NSTextAttachment { var emotionKey: String? { get { objc_getAssociatedObject(self, NSTextAttachment._emotionKey) as? String } set { objc_setAssociatedObject(self, NSTextAttachment._emotionKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } }展示时文本再转回图片收到消息后例如[飞吻]stringToEmotion用正则\\[.*?\\]找出所有方括号文本逐一查表换成图片附件并维护lengthOffset修正替换后偏移let pattern \\[.*?\\] let matches regex?.matches(in: str.string, options: [], range: NSRange(location: 0, length: str.length)) ?? [] for match in matches { let attachment NSTextAttachment() attachment.image UIImage(contentsOfFile: emotionPath) // ... 设置 bounds 后用 replaceCharacters 原位替换 }聊天列表各消息 CellTextMessageCell.swift、SystemMessageCell.swift、TimeCell.swift都在initData和计算高度时调用stringToEmotion保证气泡内显示图片表情且高度计算与显示一致。表情选择器与输入框的联动EmotionSelector.swift 用横向滚动的UICollectionView呈现三页表情每页 21 个格子第 20 行固定放删除键底部带页码指示点左右滑动手势切换页面。ChatTextView.swift 作为总控处理三个关键事件选中表情onSelect在光标位置调用EmotionHelper.insertEmotion插入附件并把光标后移 1 位删除键onDelete直接textView.deleteBackward()由于表情只占 1 字符自然整块删除发送onSend先emotionToString转回纯文本再交给上层发送同时用 KVO 监听attributedText变化来控制发送按钮的可用状态。func onSelect(emotionKey: String) { let location textView.selectedRange.location textView.attributedText EmotionHelper.insertEmotion(str: textView.attributedText, index: location, key: emotionKey) textView.selectedRange NSRange(location: location 1, length: 0) }总结这套表情系统值得借鉴的 3 个设计一符一图用NSTextAttachment让表情在文本流中只占 1 个字符删除、计数、光标移动全部免费获得正确行为存文本、展图片传输层永远是[文本]展示层才转图片天然兼容 WebSocket 纯文本协议数据驱动表情列表由 emotion.json 声明新增表情只需加图片文件和一行映射零代码改动。读懂这个模块你也就掌握了 iOS 富文本表情编辑的通用套路可以迁移到自己的 IM 或评论系统中 ✨。【免费下载链接】douyin-ios-swift抖音 iOS Swift版项目地址: https://gitcode.com/gh_mirrors/do/douyin-ios-swift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

二维矩形件排样与组批优化:从数学建模到算法实现

二维矩形件排样与组批优化:从数学建模到算法实现

2026/8/23 10:02:37

1. 问题背景与核心挑战:从“一张大板”到“高效切割”在制造业,特别是板材加工、服装裁剪、印刷制版等行业,一个看似简单却极其耗费成本的环节就是“下料”。想象一下,你面前有一张巨大的原材料板材(比如钢板、玻璃板、…

MES项目成功三要素:业务目标、数据基础与组织变革

MES项目成功三要素:业务目标、数据基础与组织变革

2026/8/23 10:02:37

如果你正在考虑或正在实施一个MES(制造执行系统)项目,心里可能正盘旋着几个最现实的问题:为什么很多MES项目投入巨大,最终却沦为“面子工程”,甚至半途而废?一个成功的MES项目,其决定…

3步跑通 ELK.js:复杂图自动布局不再靠手拖

3步跑通 ELK.js:复杂图自动布局不再靠手拖

2026/8/23 10:02:37

3步跑通 ELK.js:复杂图自动布局不再靠手拖 【免费下载链接】elkjs ELKs layout algorithms for JavaScript 项目地址: https://gitcode.com/gh_mirrors/el/elkjs 节点一多,连线就成了蜘蛛网,拖拽半天还是乱。ELK.js 把 Eclipse 的图布…

WiFi 信号分析工具 WiFiAnalyzer:从零下载安装,4 步构建并跑上设备

WiFi 信号分析工具 WiFiAnalyzer:从零下载安装,4 步构建并跑上设备

2026/8/23 11:12:40

WiFi 信号分析工具 WiFiAnalyzer:从零下载安装,4 步构建并跑上设备 【免费下载链接】WiFiAnalyzer Android application to analyze Wi-Fi signals. 项目地址: https://gitcode.com/gh_mirrors/wi/WiFiAnalyzer 想知道自家 WiFi 卡在哪条信道、信…

如何为FLUX LoRA写出好提示词:flux-lora-collection的AI绘图Prompt实战技巧

如何为FLUX LoRA写出好提示词:flux-lora-collection的AI绘图Prompt实战技巧

2026/8/23 11:12:40

如何为FLUX LoRA写出好提示词:flux-lora-collection的AI绘图Prompt实战技巧 【免费下载链接】flux-lora-collection 项目地址: https://ai.gitcode.com/hf_mirrors/XLabs-AI/flux-lora-collection flux-lora-collection 是专为 FLUX.1-dev 模型训练的一组风…

多智能体系统优势幻觉:单智能体CoT-SC技术如何实现更优推理

多智能体系统优势幻觉:单智能体CoT-SC技术如何实现更优推理

2026/8/23 11:12:40

1. 项目概述:多智能体系统的“优势幻觉”最近在AI社区里,关于多智能体(Multi-Agent)系统的讨论热度一直居高不下。从各种开源框架到层出不穷的论文,似乎都在传递一个信号:把一个大模型任务拆解成多个“智能…

实测有效:基于AIGC的免费文本降重指令方案与工作流

实测有效:基于AIGC的免费文本降重指令方案与工作流

2026/8/23 11:12:40

在实际学术写作、技术报告或内容创作中,原创性审查是绕不开的一环。无论是毕业论文查重,还是技术文档、项目报告的原创度检测,过高的重复率都可能带来麻烦。传统的人工降重耗时耗力,而市面上一些声称能“一键降重”的工具&#xf…

企业招聘系统开发:从架构设计到智能筛选实践

企业招聘系统开发:从架构设计到智能筛选实践

2026/8/23 11:12:40

1. 企业招聘系统开发全流程解析 最近刚完成一个企业自主招聘系统的开发项目,这个90393编号的项目是给某中型企业定制的校招解决方案。作为计算机专业的毕业设计选题,这类系统既有足够的复杂度来展示技术能力,又能解决真实的企业需求。不同于市…

Java面试题库:深度解析核心考点与高频问题

Java面试题库:深度解析核心考点与高频问题

2026/8/23 11:02:40

## 1. 为什么需要这样一份面试题库最近三年Java技术栈的迭代速度明显加快。从Java 17引入的switch模式匹配、记录类(Record),到Spring 6.0对GraalVM原生镜像的支持,再到Quarkus等新兴框架的崛起,面试考察的知识维度正在…

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

2026/8/23 0:02:09

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

2026/8/23 0:02:09

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

2026/8/23 0:02:09

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

2026/8/23 0:02:09

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

2026/8/23 0:02:09

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

2026/8/23 0:02:09

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/22 2:02:26

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/22 4:13:47

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/22 1:32:34

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…