iOS文字滚动:使用CATextLayer实现的跑马灯(附源码)

ops/2025/2/7 20:19:30/

引言

在 iOS 开发中,跑马灯效果(Marquee Effect)是一种常见的文本滚动效果,广泛应用于广告展示、动态消息栏、通知推送等场景。通过跑马灯效果,我们能够以流畅的方式展示超出屏幕范围的文本,提升用户体验。

通常,在 iOS 中实现跑马灯效果,我们可能会想到UILabel。然而,虽然UILabel提供了丰富的文本样式支持,它在动画和性能方面却有一定局限性。特别是在需要自定义动画效果和处理高性能的场景中,UILabel并不是最理想的选择。

此时,CATextLayer就成为了一个更灵活的替代方案。CATextLayer是一个低级的图层类,继承自CALayer,它专注于文本渲染,并且可以与 Core Animation 配合,实现高效且平滑的动画效果。相比于UILabel,CATextLayer更加轻量,且能更精确地控制动画和渲染性能,因此非常适合用于跑马灯这类需要高效动画渲染的场景。

本文将通过一个实际的例子,介绍如何使用CATextLayer实现一个简洁、流畅的跑马灯效果,帮助你在 iOS 项目中灵活运用这一技术。

CATextLayer基础

CATextLayer是Core Animation框架中的一种特殊图层(CALayer的子类),专门用于渲染文本。它与UILabel的最大区别在于,它并不直接处理用户交互和文本样式的布局,而是通过图层的方式,专注于高效的文本渲染和动画效果。

在Core Animation中,CATextLayer被设计为一个性能高效的图层,能够承载大量的文本内容并进行平滑的动画。与UILabel类不同,CATextLayer主要用于显示文本,而不涉及复杂的布局计算和视图管理,因此它非常适合用于需要高效渲染的场景,比如动画、动态图文等。

CATextLayer的主要特点:

  1. 专注于文本渲染:CATextLayer不像UILabel那样支持复杂的用户交互和动态布局,它主要负责在屏幕上渲染文本,减少了多余的开销。
  2. 高性能的文本绘制:由于其直接依赖于Core Animation,CATextLayer在渲染性能上笔UILabel更加优秀,特别是在处理大量文本和需要高帧率动画时,能够提供更平滑的效果。
  3. 支持基本的文本属性:CATextLayer支持字体、大小、颜色、对齐方式等基本的文本属性,但它并不完全支持 NSAtrributedString中的所有样式。这使得它非常适合需要简洁文本样式和高效动画的场景。
  4. 与Core Animation配合使用:CATextLayer天生与Core Animation配合,能够与其他图层(例如CALayer)进行协调,创建复杂的动画效果,如滚动、变换、透明度变化等。利用CATextLayer,可以实现诸如跑马灯、动态通知等动画效果。
  5. 不直接管理布局:与UILabel不同CATextLayer不负责复杂的自动布局或响应交互,它仅在指定的区域内渲染文本,适合用于自定义动画和轻量级显示。

通过CATextLayer,开发者可以更加灵活地控制文本的渲染和动画,尤其在需要高效且流畅显示大段文本的场景中,CATextLayer 提供了比 UILabel 更加高效的方案。

实现步骤

为了让我们自定义的跑马灯文字组件使用起来和普通的UILabel一样,可以直接继承自UILabel来构建自定义的文字自动滚动组件。在自定义的组件内部创建一个CATextLayer图层用来承载文字和执行动画。

准备工作

为了实现滚动效果,首先我们需要当前文本展示完成后所需的组件宽度和滚动速度,然后根据宽度再来创建特殊的文字图层CATextLayer以及执行滚动动画。

    /// 文字图层private var marqueeLayer: CATextLayer?/// 速度private var speed: CGFloat = 50.0
    private func setupTextLayer() {self.layer.masksToBounds = true// 清理图层clearLayer()// 计算文字宽度,优先考虑富文本var attributedText = self.attributedTextif attributedText == nil {attributedText = NSAttributedString(string: text ?? "", attributes: [.font: font, .foregroundColor: textColor])}let textWidth = attributedText?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: frame.height), options: .usesLineFragmentOrigin, context: nil).width ?? 0guard let attributedText = attributedText else {return}// 添加文字图层addMarqueeTextLayer(attributedString: attributedText, width: textWidth)if textWidth <= self.bounds.width {return}// 添加动画addMarqueeAnimation(width: textWidth, textLayer: marqueeLayer!)}override func layoutSubviews() {super.layoutSubviews()if self.bounds.size.width > 0 {setupTextLayer()}}
  1. 声明了一个CATextLayer特殊图层。
  2. 定义了滚动的速度。
  3. setupTextLayer()方法中计算文本的宽度,来决定整个文字图层是否需要滚动。
  4. 为了适应约束布局,重写layoutSubviews()方法,并在组件已经有了宽度的时候重新执行setupTextLayer()方法。

创建CATextLayer

当获取到文本内容,计算出文本宽度之后就可以根据内容和宽度来创建CATextLayer添加到UILabel的图层之上并设置布局。

    /// 添加文字图层/// - Parameters:///  - attributedString: 富文本///  - width: 文字宽度private func addMarqueeTextLayer(attributedString:NSAttributedString,width:CGFloat) {let textLayer = CATextLayer()textLayer.string = attributedStringtextLayer.contentsScale = UIScreen.main.scaletextLayer.alignmentMode = .lefttextLayer.frame = CGRect(x: 0, y: 0, width: width, height: frame.height)layer.addSublayer(textLayer)self.marqueeLayer = textLayerprint("string:\(attributedString)")textLayer.backgroundColor = UIColor.red.cgColor}
  1. 创建图层并设置图层的文字内容。
  2. 设置contentsScale这一步十分关键,否则在Retina会出现模糊。
  3. 设置frame,x和y分别从0开始,宽度为文字总宽度,高度为组件高度。
  4. 设置UILabel的原本颜色为透明色,目的是隐藏UILabel原来的显示内容。

添加动画

CATextLayer创建完成之后,我们只需要让它的最左端从组件的最右端开始执行动画,直到CATextLayer图层的最右端与组件的最左端对齐为止,为此我们需要计算起始位置和结束位置。

    /// 添加图层动画/// - Parameters:/// - width: 文字宽度/// - textLayer: 文字图层private func addMarqueeAnimation(width: CGFloat, textLayer: CATextLayer) {//添加动画let startOffset = bounds.width + width / 2.0let endOffset = -width/2.0let duration = Double(width) / Double(speed)let animation = CAKeyframeAnimation(keyPath: "position.x")animation.values = [startOffset, endOffset]animation.keyTimes = [0, 1]animation.duration = durationanimation.repeatCount = .infinityanimation.isRemovedOnCompletion = falsetextLayer.add(animation, forKey: "marqueeScroll")}
  1. 我们针对图层的position.x执行关键帧动画,那么它的起点位置应该是组件宽度+文字宽度/2。
  2. 而结束为止应该是负的文字宽度。
  3. 根据速度计算动画时长。
  4. 设置重复次数无限大,让动画一直循环。

清理图层

最后还有一个重要的方法,清理特殊图层。

    /// 清理图层private func clearLayer() {self.marqueeLayer?.removeAllAnimations()self.marqueeLayer?.removeFromSuperlayer()self.marqueeLayer = nil}

使用示例

在使用时,我们只需要像普通UILabel一样使用,支持绝对布局和相对布局。

    /// 添加跑马灯文字private func addMarqueeLabel() {let marqueeLabel = PHMarqueeLabel(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 40.0))marqueeLabel.text = "今天是一个好天气,适合出去玩耍"marqueeLabel.textColor = .whitemarqueeLabel.font = UIFont.systemFont(ofSize: 20)marqueeLabel.backgroundColor = .orangeview.addSubview(marqueeLabel)}
        /// 添加跑马灯文字private func addMarqueeLabel() {let marqueeLabel = PHMarqueeLabel(frame: .zero)let text = "今天是一个好天气,适合出去玩耍"let attributedText = NSMutableAttributedString(string: text)attributedText.addAttributes([.foregroundColor: UIColor.blue], range: NSRange(location: 0, length: 2))attributedText.addAttributes([.foregroundColor: UIColor.green], range: NSRange(location: 2, length: 2))marqueeLabel.attributedText = attributedTextmarqueeLabel.font = UIFont.systemFont(ofSize: 20)marqueeLabel.backgroundColor = .orangeview.addSubview(marqueeLabel)marqueeLabel.snp.makeConstraints { make inmake.top.equalTo(100.0)make.leading.trailing.equalToSuperview().inset(100.0)}}

效果如下:

结语

通过本文,我们探讨了如何使用 CATextLayer 实现一个高效流畅的跑马灯效果。相比于 UILabel,CATextLayer在渲染性能上更具优势,特别是在需要动态更新和动画效果时,它能够提供更加平滑的用户体验。尽管 CATextLayer 支持的文本样式有限,但对于一些简单的文本显示需求,尤其是高效动画渲染,它无疑是一个理想的选择。

在实际开发中,使用 CATextLayer 实现跑马灯效果,能够帮助我们节省性能开销,减少无谓的视图层级,同时通过 Core Animation 提供流畅的视觉体验。无论是在广告轮播、消息通知还是动态标签的场景中,CATextLayer 都能够发挥出色的表现。

当然,CATextLayer 也并非万能,对于需要高度自定义富文本样式的场景,我们仍然可以结合 UILabel 或其他控件来实现更复杂的效果。但对于大多数简洁、流畅的滚动效果,CATextLayer 是一个值得推荐的解决方案。

希望通过本文的介绍,能够帮助你在项目中更好地使用 CATextLayer来实现跑马灯效果,提升动画表现与用户体验。

https://download.csdn.net/download/weixin_39339407/90341158https://download.csdn.net/download/weixin_39339407/90341158


http://www.ppmy.cn/ops/156534.html

相关文章

【工具篇】ChatGPT:开启人工智能新纪元

一、ChatGPT 是什么 最近,ChatGPT 可是火得一塌糊涂,不管是在科技圈、媒体界,还是咱们普通人的日常聊天里,都能听到它的大名。好多人都在讨论,这 ChatGPT 到底是个啥 “神器”,能让大家这么着迷?今天咱就好好唠唠。 ChatGPT,全称是 Chat Generative Pre-trained Trans…

MTGNN论文解读

模型架构 MTGNN 由多个模块组合而成&#xff0c;目标是捕捉多变量时间序列中的空间&#xff08;变量间&#xff09;和时间&#xff08;时序&#xff09;依赖。 图学习层&#xff1a;用于自适应地学习图的邻接矩阵&#xff0c;发现变量之间的关系。图卷积模块&#xff1a;根据邻…

汽车自动驾驶AI

汽车自动驾驶AI是当前汽车技术领域的前沿方向&#xff0c;以下是关于汽车自动驾驶AI的详细介绍&#xff1a; 技术原理 感知系统&#xff1a;自动驾驶汽车通过多种传感器&#xff08;如激光雷达、摄像头、雷达、超声波传感器等&#xff09;收集周围环境的信息。AI算法对这些传感…

京准:NTP卫星时钟服务器对于DeepSeek安全的重要性

京准&#xff1a;NTP卫星时钟服务器对于DeepSeek安全的重要性 京准&#xff1a;NTP卫星时钟服务器对于DeepSeek安全的重要性 在网络安全领域&#xff0c;分布式拒绝服务&#xff08;DDoS&#xff09;攻击一直是企业和网络服务商面临的重大威胁之一。随着攻击技术的不断演化…

旅行社项目展示微信小程序功能模块和开发流程

旅行社当前旅游线路的程序(微信小程序),旨在帮助旅行社更高效地管理线下活动预订,同时为客户提供便捷的报名和查看功能。适用于短途游、团队建设等活动,支持在线预订、缴费及订单管理,可根据用户需求定制更多个性化服务,为公司提升品牌知名度与客户体验。通过简洁明了的…

Linux 内核源码can相关配置项

目录 一、配置项解释(kernel源码/net/can/Makefile)1. CONFIG_CAN2. CONFIG_PROC_FS3. CONFIG_CAN_RAW4. CONFIG_CAN_BCM5. CONFIG_CAN_GW6. CONFIG_CAN_J19397. CONFIG_CAN_ISOTP8. 总结 二、Linux can协议栈部分功能细究1. CAN Gateway1.1 原理及使用场景1.2 使用方法1.3 为什…

阿里云不同账号vpc对等连接

目录 一&#xff0c;VPC对等连接介绍 1&#xff0c;VPC功能介绍 2&#xff0c;使用场景 二&#xff0c;准备vpc,和ECS服务器 1,第一个账号vpc网络/网段 ​编辑 2&#xff0c;第一个账号下的ECS实例 ip:172.19.45.29 ​编辑 3&#xff0c; 第二个账号vpc网络/网段 4&…

亚博microros小车-原生ubuntu支持系列:18 Cartographer建图

Cartographer简介 Cartographer是Google开源的一个ROS系统支持的2D和3D SLAM&#xff08;simultaneous localization and mapping&#xff09;库。基于图优化&#xff08;多线程后端优化、cere构建的problem优化&#xff09;的方法建图算法。可以结合来自多个传感器&#xff0…