帧动画实践

帧动画

  • 基本介绍
    • 动画
    • 帧率(FPS)
    • 帧动画开发
      • 帧动画的实现方案
        • gif图实现动画
        • css实现动画
        • js实现逐帧动画
          • (1)raf介绍
          • (2)为什么建议raf(定时器和Raf区别)?
      • 实现帧动画常用的解决方案
    • demo实践
      • 使用raf实现轮播动画
      • 使用raf实现一个进度条
    • 帧率监听工具

基本介绍

本片文章以简单的case说明下,从前端开发角度什么是帧动画呢?

动画

英语:(Animation)是一种通过定时拍摄一系列多个静止的固态
图像(帧)以一定频率连续变化、运动(播放)的速度(如每秒16张)而导致肉眼的视觉残象产生的错觉,而误以为图画或物体(画面)活动的作品及其视频技术。

帧率(FPS)

帧率(英文:frame rate)是用于测量显示帧数的度量。测量单位为“每秒显示帧数”(frame per second,FPS)或“赫兹”,一般来说FPS用于描述视频、电子绘图或游戏每秒播放多少帧。

通俗来讲,以最早的电影胶片为例,电影通常是很长的胶卷,每部电影都是通过投影设备将胶片的每个画面放大呈现在大屏幕上,帧率即就是每秒能够播放的画面个数。
在这里插入图片描述
我们每次购买电脑或者相关设备时都会去关注两个指标:帧率和屏幕分辨率
帧率越大,视频画面越流畅,尤其是对游戏高端玩家,帧率直接影响玩家的游戏体验,我们通常看的电影帧率一般在24fps,手机拍摄的视频一般帧率在30fps,一般设备的最大帧率在60fps,我们可以在系统中可以查看设备当前的实时帧速率。同样在chroms的移动端模拟器中也可使查看实时帧率。虽然帧率越大视频的流畅度越好,但同时会带来视频的体积较大,因此通常调整帧率也是压缩mp4视频体积的一种方式。
在这里插入图片描述

帧动画开发

在H5开发过程中,我们经常为了给用户一个更好的用户体验,会需要实现一些动画,在实现动画时我们有以下几种实现方式:帧动画分为关键帧动画和逐帧动画都是动画的一种实现方式,我们平常接触到的都是关键帧动画。
关键帧动画:又称为补间动画,设计师只需要去关注两端的关键帧页,在关键帧上绘制一个基础形状,然后在时间帧上对另一个关键帧进行形状转变或绘制另一个形状等,然后中间的动画过程是由计算机自动生成。补间动画可以实现两个关键帧图形之间颜色、大小、形状或位置的相互变化。关键帧动画比逐帧动画制作简单,且资源体积更小。
逐帧动画:逐帧动画认为每一帧都为关键帧,在每一帧页上都需要绘制帧内容,连续播放每一帧实现动画效果。

逐帧动画:逐帧动画有称为定格动画,是一种动画技术,器原理即将每帧不同的图像连续播放,从而产生动画效果,简言之,实现逐帧动画需要两个条件:(1)相关联的不同图像,即动画帧;(2)连续播放、
在这里插入图片描述

帧动画的实现方案

在这里插入图片描述

gif图实现动画

在这里插入图片描述

gif 可以有多个动画帧,连续播放是其自身属性,是否循环也是由其本身决定的。它往往用来实现小细节动画,成本较低、使用方便。
但根据以上录屏展示(绿色部分表示帧重绘区域),帧动画会周期性引起页面的重绘(repaint), 导致页面性能较差。并且gif图在清晰度上表现较差,图片放大后锯齿毛边比较严重。因此gif实现动画适应于一些对画面细节要求较低的动效上,开发成本相对较低,使用起来方便。

css实现动画

在css3中的Animation动画可以实现逐帧动画,使用animation-timing-function 的阶梯函数 steps(number_of_steps, direction) 来切换图片实现逐帧动画的连续播放。我们可以在@keyframes中定义每一帧的动画效果。例如,我们在不同的step替换背景图片,来完成图片连续播放,实现动画。这种方式只适用于帧数较少的动画实现。

.animate {width: 300px;height: 300px;background-repeat: no-repeat;background-image: url(frame.png);animation: frame 333ms steps(1,end) both infinite;
}
@keyframes frame {0% {background-image: url(frame0.png);}10% {background-image: url(frame1.png);}20% {background-image: url(frame2.png);}35% {background-image: url(frame3.png);}40% {background-image: url(frame4.png);}50% {background-image: url(frame5.png);}60% {background-image: url(frame6.png);}70% {background-image: url(frame7.png);}80% {background-image: url(frame8.png);}90% {background-image: url(frame9.png);}100% {background-image: url(frame10.png);}
}

但此种方式需要有多张图片,请求每张图片会导致多次请求http,并且每张图片切换首次加载时会出现闪烁的情况,切多张图片维护起来成本较高,因此,我们可以采用合成雪碧图等方式,修改图片位置,来实现图片的逐帧播放。
在日常开发中,我们通常会采用css逐帧动画方案实现一些类似于大小缩放、位移、渐变等样式属性的简单动画,如按钮呼吸动画,闪烁动画,元素漂移、loading动画等效果,我们通过想设计师给的动画参数即可以完成动效效果,性能相对于动图等较高。

js实现逐帧动画

js实现逐帧动画的方案较多,最直接的方式是通过js动态去修改img标签的src或者修改元素样式完成动画的连续播放,其次就是canvase绘制。

js实现动画需要关注的点就是循环去触发函数,实现驱帧效果?
在动画驱动的时候我们可以采用requestAnimationFrame(raf)和setTimeOut(定时器)两种方案去驱动step帧动画。

在日常的动画实现上我们通常建议采用raf方式

(1)raf介绍

window.requestAnimationFrame()

告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行

(2)为什么建议raf(定时器和Raf区别)?

(1)执行时机:定时器是指定时间后完成帧画面的切换,不依赖于设备帧率,通常我们为了使切换帧和屏幕刷新同频,我们的时间间隔采用1000/60(通常的屏幕帧率为60fps),但刷新率在不同设备下可能存在不同,因此按60fps设置固定的时间间隔,可能会存在仍和帧率不同步的问题,raf是的执行是根据屏幕的刷新帧率步伐走,在每一次页面重绘前通知系统完成raf的回调。
(2)丢帧情况:定时器的执行不依赖于设备帧率,如果回调方法的执行和系统的刷新时机步调不一致,就可能会导致中间某一帧的操作被跨越过去,而直接更新下一帧的图像,产生丢帧的情况。而raf的执行依赖于系统步伐,能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。
(3)性能:在页面退入后台的时候,即未激活状态的时候,定时器会仍然在后台执行任务,但此时的页面是非激活状态,因此在后台刷新帧画面是没有任何意义的,因此是一定程度上CPU资源的占用,因此在开发过程中出于性能考虑,需要在页面未激活态的时候将定时器暂停掉,进入页面的时候再重启定时器刷新帧画面。而raf是和设备的帧率是相同步的,当页面处于未激活态的时候,屏幕刷新进程会被中断,因此raf动画任务也会中断,因此减少资源的占用。

实现帧动画常用的解决方案

方案技术点工具库特点
Apngapng-js开源库体积较大,需要注意体积的压缩
Lottielottie-web开源库体积适中,适用于处理交互较为复杂的交互动效lottie-web的包体积较大
视频video/透明视频原生video(1)体积较小,性能较好(2)safari 和 chrome 中可能无法自动播放

demo实践

使用raf实现轮播动画

目标实现一个无缝轮播组件,我采用raf驱动的形式完成视频的轮播动画。避免生硬,我们设定每次动画过度时间为300ms。由于以上描述大部分的屏幕帧率是60HZ,因次我们设定动画间隔为1000ms/60=17为动画间隔,以这个循环间隔重绘的动画时比较平缓的,因为这个速度最接近屏幕的最高限速。

采用raf做位移驱动,完成位移动画
定义一个raf方法:

// 当不支持raf时采用定时器完成动画
function rafPolyfill(fn: TimerHandler) {const id = setTimeout(fn, 1000/60);return id;
}function raf(fn: FrameRequestCallback) {const requestAnimationFrame = window.requestAnimationFrame || rafPolyfill;return requestAnimationFrame.call(window, fn);
}

定义每次帧刷新的回调函数,为了实现在每一次刷新前都更新下一次刷新,在回调函数中再次调用raf方法,完成刷新,直到动画播放完成。

export function animateTo(options: { to: any; from: any; duration: any; callback: any; }) {const { to, from, duration, callback } = options;if (to === from) {callback(to, true);return;}let start = 0;const during = Math.ceil(duration / 17);let rafId: number;const step = () => {const value = cubicEaseOut(start, from, to - from, during);start++;if (start <= during) {callback(value);rafId = raf(step);} else {callback(to, true);}};step();return () => {cancelRaf(rafId);};
}

使用raf实现一个进度条

在这里插入图片描述

<template><div class="progress-container"><span class="progress-desc">正在loading中......</span><div class="progress-bar"><divclass="progress-bar progress-status-bar":style="{ transform: `translateX(${progressWidth}%)` }"></div></div><span class="progress-desc progress-value">{{ progressWidth }}<img class="percent-img" src="../assets/icon/percent.png"/></span></div>
</template>
<script>
export default {data() {return {progressWidth: 0,};},mounted() {this.getProcess();},methods: {getProcess() {const timer = window.requestAnimationFrame(() => {if (this.progressWidth <= 99) {// 进度条长度设置this.progressWidth++;this.getProcess();} else {this.progressWidth = 0;this.getProcess();window.cancelAnimationFrame(timer);}});},},
};

帧率监听工具

  • 移动端
    以安卓为例:打开手机开发者工具 =》选择“功能监测”=》开启 “Frame Rate Monitor Tools”
    在这里插入图片描述
  • pc端
    打开控制台=》更多工具=》打开“渲染”界面=》开启“帧渲染统计信息”(vscode编译器)
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/598182.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通讯录----顺序表版本

1.通讯录的实现逻辑 对于通讯录&#xff0c;我们做的无非就是初始化&#xff0c;销毁。添加联系人数据&#xff0c;修改联系人数据&#xff0c;删除联系人数据&#xff0c;查找联系人数据&#xff0c;展示联系人数据&#xff1b; 这个不就和我们的顺序表的逻辑如出一辙吗&…

Lesson1--数据结构前言

1. 什么是数据结构&#xff1f; 2. 什么是算法&#xff1f; 3. 数据结构和算法的重要性 4. 如何学好数据结构和算法 5. 数据结构和算法书籍及资料推荐 1. 什么是数据结构&#xff1f; 数据结构(Data Structure) 是计算机存储、组织数据的方式&#xff0c;指相互之间存在一…

虚拟机 ubuntu 20.04 git 设置代理的方法

前言 ubuntu 20.04 虚拟机中 Git 访问 github 或者其他的 git 仓库&#xff0c;大部分情况下速度很慢&#xff0c;并且容易掉线 如果 主机上使用了代理软件&#xff0c;但是虚拟机 ubuntu 中 Git 访问 git 仓库依旧是很慢 【问题】如何设置 虚拟机 ubuntu 的 Git 代理&#x…

从概念到实践:探索独立站在当代电商中的关键作用

随着数字化时代的到来&#xff0c;电子商务已成为全球商业生态的核心组成部分。在这个不断变化的市场中&#xff0c;独立站作为企业建立在线身份和拓展业务的强大工具&#xff0c;正逐步展现出其不可替代的价值。 从概念到实践&#xff0c;本文将深入探索独立站在当代电商中的关…

vivado 系统内逻辑设计调试流程

系统内逻辑设计调试流程 Vivado 工具提供了诸多功能 &#xff0c; 用于在真实硬件器件中调试系统内设计。系统内调试流程包含 3 个不同阶段 &#xff1a; 1. 探测阶段 &#xff1a; 确定设计中要探测的信号和探测的方法。 2. 实现阶段 &#xff1a; 完成设计实现 &…

Redis的主从复制和哨兵模式

目录 引言 一、主从复制 1.1 概念 1.2 作用 1.3 流程 1.4 环境搭建 二、哨兵模式 2.1 概念 2.2 原理 2.3 作用 2.4 故障转移机制 2.5 主节点的选举 2.6 环境搭建 2.6.1 修改Redis 哨兵模式的配置文件(所有节点操作) 2.6.2 启动哨兵模式 2.6.3查看哨兵信息 2.6.…

SystemC入门学习Demo用例的工程化配置

背景&#xff1a;对不同的用例文件&#xff0c;使用CMakeLists.txt进行工程化管理的演示&#xff0c;这样开发者可以更加关注在代码开发上。 1&#xff0c;首先安装好系统环境的systemC库&#xff1a;ubuntu系统安装systemc-2.3.4流程-CSDN博客 2&#xff0c;准备好一个demo用…

OSPF基础实验

一、实验拓扑 二、实验要求 1、按照图示配置IP地址 2、R1&#xff0c;R2&#xff0c;R3运行OSPF使内网互通&#xff0c;所有接口&#xff08;公网接口除外&#xff09;全部宣告进 Area 0&#xff1b;要求使用环回口作为Router-id 3、业务网段不允许出现协议报文 4、R4模拟互…

蓝桥杯23年第十四届省赛-异或和之和|拆位、贡献法

题目链接&#xff1a; 蓝桥杯2023年第十四届省赛真题-异或和之和 - C语言网 (dotcpp.com) 1.异或和之和 - 蓝桥云课 (lanqiao.cn) 参考题解&#xff1a; 蓝桥杯真题讲解&#xff1a;异或和之和 &#xff08;拆位、贡献法&#xff09;-CSDN博客 洛谷P9236 [蓝桥杯 2023 省 A]…

解决windows下Qt Creator显示界面过大的问题

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;QT❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 问题描述 解决方法 1、右击此电脑--->属性 2、点击高级系统设置--->点击环境变量 3、 找到系…

Java Netty个人对个人私聊demo

一、demo要求 1&#xff09;编写一个Netty个人对个人聊天系统&#xff0c;实现服务器端和客户端之间的数据简单通讯&#xff08;非阻塞&#xff09; 2&#xff09;实现单人对单人聊 3&#xff09;服务器端&#xff1a;可以监测用户上线&#xff0c;离线&#xff0c;并实现消…

Python实现【坦克大战】+源码分享

写在前面&#xff1a; 坦克大战&#xff0c;这款经典的电子游戏&#xff0c;无疑是许多80后和90后心中不可磨灭的童年记忆。它不仅仅是一款游戏&#xff0c;更是那个时代科技娱乐方式的缩影&#xff0c;见证了电子游戏行业的起步与发展。 在那个电脑和网络尚未完全普及的年代…