二十一.核心动画-应用 实现直播间内飘心动画

引言

在如今的直播平台和社交应用中,用户互动不仅限于文字和语音,更多的创意动画和特效被引入来提升用户的沉浸感和参与感。特别是在直播场景中,动态效果如屏幕飘心、点赞、烟花等互动特效,已成为增强直播氛围、吸引观众注意力的重要手段。

本篇博客将重点探讨如何在直播间内实现一个经典的“飘心”动画效果。当用户点击屏幕时,心形图案会随机飘动,增加直播互动的趣味性。在这篇文章中,我将介绍如何通过自定义动画来实现这一效果,解决如何控制每次点击的心形数量、轨迹、随机性等问题,并通过实际代码演示如何构建这个互动效果。

通过这个例子,我们可以进一步了解核心动画相关知识在实际项目开发中的应用,深入理解如何精细地控制动画的路径、持续时间、数量等参数,从而提升用于体验。

需求分析

本需求的核心是:当用户点击直播间的屏幕时,屏幕上会随机生成一个心形图案,并沿着一个随机轨迹向上飘动。每次点击时,系统能够处理并发的多个点击事件,确保每个心形的动画都能够流畅显示,并在适当的时间消失。

为了实现这一效果,关键点如下:

  1. 点击屏幕生成多种图案:每次点击屏幕时,都要生成随机的图片。
  2. 轨迹随机:飘心的图案要颜色以及的轨迹飘动。为了避免所有心形朝着相同方向飘动,可以对每个心形设置不同的随机偏移量,控制其飘动方向和路径。
  3. 动画效果控制:每个图案的飘动轨迹需要时平滑的,并带有一定的随机性,以避免路径单一化。图案的透明度也会随着时间变化直到消失。
  4. 性能考虑:由于可能存在较高的并发,我们需要确保每次生成的心形动画不会导致界面卡顿或资源浪费。

通过解决上述需求,我们能够为直播间的观众带来一个生动的互动效果,同时增强用户在观看直播过程中的参与感。

实现方案

我们使用Demo先来实现一个简易版,因为在直播间的中的实现,需要处理各种消息和一次显示多个飘心动画等许多复杂情况。

准备工作

在简易版本中,我们实现定义飘心动画执行的最大个数,以及正在显示的个数,来控制最大数量。

class MWHeartFloatView: UIView, CAAnimationDelegate {
    
    /// 动画最大堆积个数
    private let maxCount = 1000
   /// 正在显示个数
    private var showingCount = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = .red
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        showHeartFloatAnimation()
    }
    ...
}
  1. 定义动画执行的最大个数。
  2. 定义变量记录正在显示的个数。
  3. 重写屏幕点击方法,点击后执行飘心动画。

创建内容图层

为了实现屏幕飘心的效果,我们选择使用 CALayer 来显示心形的图片内容。相比于 UIImageView,CALayer 更加轻量和高效,特别适合用于需要频繁创建和销毁的场景。在这个需求中,我们可能会同时处理多个心形的生成与动画,因此 CALayer 的优势尤为突出。它不会像UIImageView 那样占用过多内存和资源,而且能更高效地与图形渲染引擎配合,确保动画流畅执行。

CALayer 不仅支持图像渲染,还能直接与 Core Animation 中的动画框架结合,提供更细粒度的动画控制。通过使用 CALayer,我们可以为每个心形图层创建个性化的动画路径,控制其位置、透明度、旋转等属性,而无需依赖视图层级结构的复杂操作。这使得在处理大量动画时,性能得到了显著提升,避免了频繁创建视图导致的渲染负担。

通过这种方式,我们不仅可以保证每个心形的渲染和动画效果流畅,还能够最大化地减少内存消耗和CPU开销,从而优化用户体验,尤其是在并发点击的高频率场景下,CALayer 展现出其出色的性能优势。

    private func showHeartFloatAnimation() {
        showingCount = showingCount + 1
        if showingCount > maxCount {
            return
        }
        let name = "like_heart="
        let imageName = name + String(format: "%02d", arc4random() % 20 + 1)
        let image = UIImage(named: imageName)
        let layer = CALayer()
        layer.contents = image?.cgImage
        let width = 24.0 + CGFloat(arc4random() % 5)
        let x = MW_SCREEN_WIDTH - 24.0
        let y = MW_SCREEN_HEIGHT - MW_BOTTOM_SAFE_HEIGHT - 45.0
        layer.frame = CGRect(x: x, y: y, width: width, height: width)
        layer.contentsScale = UIScreen.main.scale
        self.layer.addSublayer(layer)
....

}
  1. 修改显示数量,来控制飘心动画最大同时显示个数。
  2. 创建图层并设置寄宿图内容添加到指定位置。

添加动画

由于动画内容具有随机性,并且涉及多个维度的变化,我们选择采用动画组(CAAnimationGroup)的方式,将多个动画效果结合在一起,从而实现更加丰富和复杂的飘心效果。

具体来说,除了位置动画外,我们还将缩放和透明度的变化与位置的动画同步执行。通过这种方式,每个心形在飘动的过程中不仅会随机沿不同轨迹飘动,还会随着动画的进行逐渐放大或缩小,透明度也会随之变化,增强动态感和自然感。例如,心形可能会在飘动时稍微放大,模拟真实的浮动效果,而在飘动过程中透明度逐渐减少,最终消失,从而更贴合现实中的物理表现。

为了实现位置的随机性,我们在动画中加入了随机路径的功能,使每个心形沿着不同的轨迹飘动。通过为每个心形创建独立的路径并加入随机的起始位置和控制点,确保每个心形的飘动路线都不完全相同。随机性不仅增加了视觉上的多样性,还能使每次用户点击时,屏幕上的心形效果都呈现出不同的轨迹,避免了重复和单调的动画效果。

这些动画通过 CAAnimationGroup 组合在一起,使得多个动画能够同时执行,同时又不互相干扰,保证了效果的流畅性与同步性。利用动画组的强大功能,我们能够确保每个心形在飘动的过程中,位置、透明度和缩放的变化能够无缝衔接,最终呈现出一个生动、自然的动画效果。

   private func showHeartFloatAnimation() {
       ....
        // 1.缩放动画,由小变大
        let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
        scaleAnimation.fromValue = 0.1
        scaleAnimation.toValue = 1.0
        scaleAnimation.duration = 0.3
        scaleAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        //2.透明度动画,由不透明到透明
        let opacityAnimation = CABasicAnimation(keyPath: "opacity")
        opacityAnimation.fromValue = 1.0
        opacityAnimation.toValue = 0.0
        opacityAnimation.duration = 2.0
        opacityAnimation.isRemovedOnCompletion = true
        //3.轨迹动画,随机 贝塞尔曲线
        let pathAnimation = CAKeyframeAnimation(keyPath: "position")
        pathAnimation.calculationMode = .paced
        pathAnimation.fillMode = .forwards
        pathAnimation.isRemovedOnCompletion = false
        let path = UIBezierPath()
        let startPoint = layer.position
        path.move(to: startPoint)
        // 随机生成目标点
        let endX = x - 30 + CGFloat(arc4random() % 60)  // 随机左右偏移
        let endY = y - 200 - CGFloat(arc4random() % 20)  // 向上偏移200,再加上随机的微小偏移
        let endPoint = CGPoint(x: endX, y: endY)
        // 改为三次贝塞尔曲线,使用多个控制点来让路径更平滑
        let controlPoint1 = CGPoint(x: startPoint.x + CGFloat(arc4random() % 100) - 50, y: startPoint.y - 100)
        let controlPoint2 = CGPoint(x: endX + CGFloat(arc4random() % 100) - 50, y: endY - 50)
        path.addCurve(to: endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
        pathAnimation.path = path.cgPath
        pathAnimation.duration = 2.0
        // 组合动画
        let animationGroup = CAAnimationGroup()
        animationGroup.duration = 2.0
        animationGroup.animations = [scaleAnimation, opacityAnimation, pathAnimation]
        animationGroup.delegate = self
        animationGroup.isRemovedOnCompletion = false
        animationGroup.fillMode = .forwards
        layer.add(animationGroup, forKey: nil)
        animationGroup.setValue(layer, forKey: "heartLayer")
    }
  1. 缩放动画,用于飘心图案一出现的动画,由小变大。
  2. 透明度动画,用于飘心逐渐消失的效果。
  3. 位置动画,通过随机的结束位置,控制点1,控制点2, 构建三次贝塞尔曲线。
  4. 将三个动画组合并添加到指定图层。

动画结束

动画结束后,首先需要修改正在显示的动画图层个数,并移除图层的动画,以及从父图层移除图层。释放整个飘心图案的图层。

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        showingCount = showingCount - 1
        if  let layer = anim.value(forKey: "heartLayer") as? CALayer {
            layer.removeAllAnimations()
            layer.removeFromSuperlayer()
        }
        
    }

结语

通过本篇博客的介绍,我们实现了一个简单而有趣的飘心动画效果,展示了如何使用 CALayer 和 CAAnimationGroup 结合多个动画来提升用户体验。在实际应用中,通过合理的路径随机化、动画维度的组合和性能优化,我们能够为直播间或社交应用带来更加生动的互动效果。希望通过这个示例,读者能够更深入理解如何在 iOS 中灵活使用动画技术,同时激发更多创意,在应用中实现丰富的动态效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值