【亚洲必赢官网】美术死不瞑目种类之SVG推锅技巧,认识一下动画片系统

说说大家都如数家珍的网页动画技术

2015/12/07 · CSS,
HTML5,
JavaScript · 1
评论 ·
动画

原稿出处:
大搜车前端团队博客   

实则工作中,SVG一大半是用<svg>+<defs></defs>(或者symbol)+<use></use>+</svg>的咬合来行使的,defs
顾名思义就是「definitions」定义,大家得以把多如牛毛再一次性质高的元素,放入defs
元素内,让它成为一个足以重复使用的物件。而symbol越多的只是包涵单个图标。

1.前言

SVG,即Scalable Vector Graphics
可伸缩矢量图形。那种图像格式在前者中一度采用的越发普遍了,而在移动端的开发中,碰到有的繁杂的自定义控件或者动画片效果,大家就可以设想让美工出套SVG图,再依照一定的覆辙去分析即可。

动画,顾名思义,就是能“动”的画。
人的眼眸对图像有短暂的记念效应,所以当眼睛看看多张图纸延续火速的切换时,就会被认为是一段连接播发的动画了。

前言

从远古手绘翻书动画,到胶片电影,再到多张静态图合成 gif,
那一个都离不开一个术语叫

也就是我们须要绘制每一帧,然后决定一下帧与帧之间的日子间隔。

只是相邻两帧之间的变迁并不大,重复绘制浪费体力,
幸好总结机代码可以复制粘贴,然后修改一下改变的地点就可以了。

等等,好像何地不对。

电脑代码除了可以复制粘贴,还有抽象能力。
大家得以把需求复制粘贴的代码交给总括机来再一次执行。
把要求转移的地方,交给总结机来运算。

而网页中拥有运算能力的只有JS,其余的就只可以是概念一下参数,剩下的就付给浏览器了。

那就是 JS 算编程,而 HTML、css 不算编程的由来。
连锁研究,回复内容+关键字#你丫才码农#

1、SVG使用格局

随便哪一类艺术,svg都必须作为根标签

  • 外链格局
    那种方法是先定义好一个svg文件,再在html或css中引入。

// test.svg
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <circle cx="100" cy="100" r="40" fill="red"></circle>
</svg>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SVG</title>
</head>
<body>
         ![](test.svg)
</body>
</html>

外链的措施只有是将svg元素作为一个图纸,无法采用JS对其做一些操作,如改变大小颜色等。

  • 内联形式

<div id="div1">
    <svg width="100%" height="100%" >
        <circle cx="100" cy="100" r="40" fill="red" id='circle'></circle>
    </svg>
</div>

内联形式得以向操作普通html元素一样通过getElementById获得dom,再通过setAttribute方法做属性操作:

<script type="text/javascript">
      var c = document.getElementById('circle');
      c.setAttribute('fill','blue');
</script>

2.Vector Drawable

比如说,中国太古的“走马灯”,就是用的那么些规律。
稍稍人还会在一个剧本每页上手绘一些卡通,当疾速翻页的时候,也会师到动画的功效,比如:

开始

网页动画可以通过以下二种办法贯彻(gif、flash 除外),

作者知识面有限,如有遗漏,请留言公告本人。
相关商讨,回复内容+关键字#网页动画实现方式#

  • css3 动画
  • SVG 动画
  • JS 动画(包涵 css、SVG 的性质修改完毕的卡通)

作者认为 canvas、webGL 只好算是一种绘图形式。
他们的卡通也都是经过 JS 修改参数来促成的。
相关探讨,回复内容+关键字#canvas动画#

最早 JS 通过 setTimeout() 或者 setInterval() 方法设置一个小时,
来控制帧与帧之间的岁月间隔。

  • setTimeout() 间接用跳出来终止下一帧。
  • setInterval() 使用 clearInterval() 来裁撤周期执行。

然则这么效果兴许不够流畅,且会占用额外的资源。
连锁研究,回复内容+关键字#你ST设置几毫秒#
参考:

新生,有了一个requestAnimationFrame(),让浏览器决定最优帧速率选择绘制下一帧的最佳时机
requestAnimationFrame()cancelAnimationFrame() 来结束。

由此大家来改变一下思维方法,既然帧与帧之间的日子间隔不用考虑了,那就关心一下变更速率吧。

  • Partial support refers to lacking cancelAnimationFrame support.
  • Supports webkitCancelRequestAnimationFrame rather than
    `webkitCancelAnimationFrame.

— caniuse.com

好了,动画讲完了,你去找个学科看《canvas 绘图》?

别介,那才刚刚开头。

日益的,大家发现有些简约动画只是在修改多少个 css
属性,而且只是在两多个状态之间往来变换。
大气的体力却荒废在七个景况间的补间状态函数上,而且品质犬牙相制。

来来来,那种业务就交由浏览器嘛。

2、defs & use

  • 实例1:简单组合

<defs>
  <rect id="rect1" width="100" height="50" x="10" y="10" fill="#c00"/>
</defs>
<use xlink:href="#rect1"/>
<use xlink:href="#rect1" x="110"/>

亚洲必赢官网 1

【亚洲必赢官网】美术死不瞑目种类之SVG推锅技巧,认识一下动画片系统。主导构成

  • 实例2:复杂组合

<defs>
    <g id="g1">
          <rect id="rect1" width="100" height="50" x="10" y="10" fill="#c00"/>
          <circle id="circle1" cx="30" cy="30" r="10" fill="#00c"/>
    </g>
</defs>
<use xlink:href="#g1"/>
<use xlink:href="#rect1" x="110"/>
<use xlink:href="#circle1" x="210"/>

亚洲必赢官网 2

复杂组合

  • 实例3:渐变

<defs>
   <linearGradient id="a1">
     <stop offset="5%" stop-color="#F00" />
     <stop offset="95%" stop-color="#ff0" />
   </linearGradient>
</defs>
<rect x="50" y="250" width="100" height="100" stroke="#000" stroke-width="5" fill="url(#a1)"></rect>
<circle cx="220" cy="300" r="50" stroke="#000" stroke-width="5" fill="url(#a1)"></circle>
<rect x="290" y="250" width="100" height="100" stroke="url(#a1)" stroke-width="5" fill="none"></rect>

亚洲必赢官网 3

渐变

  • 实例4:路径

<defs>
  <path id="a1" d="M0 50 C150 150 100 -50 300 50" stroke="#000" fill="none"/>
</defs>
<text>
   <textPath xlink:href="#a1">这是随路径跑的文字,很酷吧
  </textPath>
</text>

亚洲必赢官网 4

路径

  • 实例5:裁切

<defs>  
  <clipPath id="a1">
  <rect x="0" y="0" width="200" height="100" />
</clipPath>
</defs>
<circle cx="100" cy="100" r="100" clip-path="url(#a1)" fill="#000" />

亚洲必赢官网 5

裁切

  • 实例6:遮罩

<defs>
  <mask id="mask1"> 
    <rect  x="50" y="50" width="100" height="100" fill="#ccc"/>
    <rect  x="150" y="150" width="50" height="50" fill="#fff"/>
  </mask> 
</defs>
  <rect id="box1" x="50" y="50" width="150" height="150" fill="#0f0"/>
  <rect id="box2" x="50" y="50" width="150" height="150" fill="#f00" mask="url(#mask1)"/>

亚洲必赢官网 6

遮罩

  • 实例7:标志marker

<defs>
  <marker id="r" viewBox="-10 -10 70 70" refX="25" refY="25" markerWidth="15" markerHeight="15" orient="auto" >
      <circle fill="#fff" stroke="#000" stroke-width="10" cx="25" cy="25" r="25"/>
  </marker>
    <marker id="g" viewBox="0 0 50 50" refX="25" refY="25" markerWidth="10" markerHeight="10" orient="45" >
      <rect fill="#0a0" width="50" height="50"/>
  </marker>
  <marker id="b" viewBox="-10 -10 70 70" refX="25" refY="25" markerWidth="15" markerHeight="15" orient="auto" >
      <circle fill="#f99" stroke="#f00" stroke-width="10" cx="25" cy="25" r="25"/>
  </marker>
</defs>
<polyline points="20,100 50,100 80,20 110,80 140,30 170,100 200,100" fill="none" stroke="black" stroke-width="1" marker-end="url(#b)" marker-start="url(#r)" marker-mid="url(#g)"></polyline>

亚洲必赢官网 7

marker

  • 实例8:滤镜

<defs>
<filter width="200" height="200" x="0" y="0" id="blur" filterUnits="userSpaceOnUse">
  <feGaussianBlur stdDeviation="5" />
</filter>
</defs>
<rect x="30" y="30" width="70" height="70" fill="#a00" filter=url("#blur") />

亚洲必赢官网 8

滤镜

2.1 矢量图与位图

先介绍下矢量图像和位图图像的界别

1.矢量图像:SVG是W3C 推出的一种开放标准的文本式矢量图形描述语言,他是基于XML的专门为网络而设计的图像格式
SVG是一种采用XML来描述二维图形的语言,所以它可以直接打开xml文件来修改和编辑。 

2.位图图像:位图图像的存储单位是图像上每一点的像素值,因而文件会比较大,像GIF、JPEG、PNG等都是位图图像格式。

也就是说,若是使用矢量图,就不需求针对差异dpi的配备浮现不一致精度的图形了,是还是不是很便利啊?

亚洲必赢官网 9

css3 动画

可以推行补间状态的尺码是,属性值可以转换成数值,那样就能加入运算。如:

  • 颜色(color,background-color,border-color…)
  • 长度/大小(width,height,font-size,border-width,border-radius…)
  • 透明度(opacity)
  • 堆叠顺序(z-index)你吖补间它有毛用

而不可能加入运算就意味着无法拿来补间状态,也就是没有中间状态,如:

  • position(absolute、fixed、relative…)
  • background-image(一个规定的 url)

一拍脑门就能体悟,创设一个补间动画的标准化有:

  • 始发情形
  • 得了状态
  • 推行时间
  • 补间效果

万一有个方块,宽度从 10px 变成 100px。

开班境况吧,在原 css 里就可以定义了 width: 10px

利落状态呢,大家得以经过用 JS 直接改动 width 值,或者伸张一个 class
选择器的艺术,
或者是 :hover 等其他代表景况的伪类,让 width: 100px

而此时,你要求一个补间动画属性来申明 执行时间补间效果
它就是 transition,普通话译作 过渡,就是自个儿所说的补间的情趣。

transition 为以下属性的简写

  • transition-property 规定哪个属性应用过渡
  • transition-duration 执行时间
  • transition-timing-function 补间效果,默认为 ease
  • transition-delay 延迟多少时间开始

参考:

Support listed is for transition properties as well as the
transitionend event. The prefixed name in WebKit browsers is
webkitTransitionEnd

— caniuse.com

css3 还提供了一个 animation 属性来创立更丰硕的自定义动画,而缩减 JS
的参加。

比如:

  • 你想一个卡通中具备多个情景
  • 各种情形修改的属性值较多
  • 巡回播放
  • 逆向播放
  • 可活动开首,可中途抛锚

animation@keyframes 协作使用。

@keyframes 用来定义动画,animation 则可以多处选择,他们通过一个 name
来三番五次互相,
因此 @keyframes 必要求起个名字,而 animation 则有个
animation-name

animation 在应用时,你能够自定义它:

  • animation-duration 执行时间
  • animation-time-function 补间效果,默认是 ease
  • animation-delay 延迟多少时间开始
  • animation-iteration-count 循环播放次数
  • animation-direction 是否在下一周期逆向播放
  • animation-play-state
    动画是否暂停,通过它,可以实现是否自动播放。要中途暂停的话,就要修改值,通过伪类或 JS 实现
  • animation-fill-mode 这几个特性倒是有点出乎意料之外,请自行钻研利用情状

看得出 w3c
规范制定者们考虑到大家要用起来不难吗,基本上和大家思考格局一样。

落到实处动画的多个情景是在 @keyframes 定义时达成的。

采用 0%~100% 的分开方式,大家就毫无在 执行时间 之外考虑时间难点了。

参考:

Partial support in Android browser refers to buggy behavior in
different scenarios.

–caniuse.com

3、控制svg

  • CSS 方式
    svg元素和html元素一样,都得以用class属性添加类名来决定样式,只是对于svg元素而言,可控制的体裁较少,常见的有fill,stroke,stroke-width
    ,opacity以及transform,看一个例子:

    //定义区
    <svg>
      <symbol id="ic"> 
          <path fill="#000" d="..."/> 
      </symbol> 
    </svg>
    //使用区
    <svg class="icon" viewBox="0 0 100 125"> 
       <use class="ic-1" xlink:href="#ic" x="0" y="0" /> 
    </svg> 
    <svg class="icon" viewBox="0 0 100 125">
       <use class="ic-2" xlink:href="#ic" x="0" y="0" />
    </svg>
    //定义样式
    .icon { width: 100px; height: 125px; }
    use.ic-1 { fill: skyblue; } 
    use.ic-2 { fill: #FDC646; }
    svg path { fill: inherit; }    //防止.ic-1,.ic-2设置的fill被path覆盖
    

亚洲必赢官网 10

symbol元素和defs大约,都是用来组成元素的,但symbol更多的用来单个图标的结合

  • JS 方式
    要在SVG内动态新增<path>或<rect>等要素,要选拔createElementNS,而不是createElement,因为svg和html不在同一个命名空间里。

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    </head>
    <body>
        <svg id="s" xmlns="http://www.w3.org/2000/svg"/>
        <script type="text/javascript">
            function makeSVG(tag, attrs) {
                var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
                for (var k in attrs)
                    el.setAttribute(k, attrs[k]);
                return el;
            }
            var circle= makeSVG('circle', {cx: 100, cy: 50, r:40, stroke: 'black', 'stroke-width': 2, fill: 'red'});
            document.getElementById('s').appendChild(circle);
        </script>
    </body>
    </html>
    

2.2 Vector Drawable简介

在Andoird中,SVG的贯彻情势就是Vector
Drawable。那是个在5.0时扩大的新类,所以对前边版本的协作会略微标题,之后会单独拎出来讲。
对峙于常见的Drawable来说,Vector Drawable有以下多少个好处:

(1)Vector图像可以自动进行适配,不需要通过分辨率来设置不同的图片。
(2)Vector图像可以大幅减少图像的体积,同样一张图,用Vector来实现,可能只有PNG的几十分之一。
(3)使用简单,很多设计工具,都可以直接导出SVG图像,从而转换成Vector图像 功能强大。
(4)不用写很多代码就可以实现非常复杂的动画 成熟、稳定,前端已经非常广泛的进行使用了。

走马灯

SVG 动画

css3 动画属性只管得住自己的 css 属性,SVG 绘制的图纸,还得 SVG
自己解决。而对于 SVG 的 css 样式,一般二种皆可。

SVG 大大们的盘算格局就有点绕了,竟然提供了 5 种动画 标签让我采取:

  • set 相当于 animate 的 calcMode="discrete",忽略
  • animate
  • animateColor 相当于 animate 的 attributeName="color",忽略
  • animateTransform
  • animateMotion

俺们先来探视和 css3 最像的 animate 标签,拥有的质量有

  • attributeName 规定哪个属性应用过渡
  • from 开始状态
  • to/by 结束状态,至少出现一个
  • values 多个状态时,忽略 from/to/by
  • begin 延迟多少时间开始
  • dur 执行时间
  • calcMode,keyTimes,keySplines 自定义补间效果
  • repeatCount,repeatDur 循环播放次数/持续时间

额,大约就是如此,下一个啊。

animateTransform 首借使为了 attributeName="transform"
跟 css3 动画组成 transform 变换类似,多了一个 type="scale"
属性用来分歧相关参数。

animateMotion 是 SVG 甩 css3
动画一条街的雄强技能,可以让SVG各样图片沿着一定的 path 路径运动。

SVG 动画比 css 动画更强劲,所以也更复杂。

细分成这 5
类标签,大致是性质考虑,人工简单区分一下数值、颜色、变换,可以为总结机省去大批量的不行运算。

作者在此地也不能讲的更详细,估量您也没看太明白
指出阅读:

4、svg最佳实践

在工作中svg使用最多的情景仍旧当小图标使用,替换诸如纯图片、iconfont图标等方案。使用内联svg的优势在于:1、少发四次http请求;2、放大不会变形;3、易于用JS控制,比iconfont更灵敏。

最佳做法(SVG sprite):

  • 1、将有着须求运用的小图标统一定义在svg下,该svg要安装display:none,每个小图标用symbol包围,每个symbol取一个id,方便后续调用;
  • 2、使用svg+use的法门调用,use中用属性xlink:href=’#id’来引用相应图标,能够给每个svg取一个类名,方便css和js动态控制;
  • 3、通过getElementById的点子赢得须求转移属性的use元素,为其动态增进或删除相应的类名;
  • 4、添加的类名最后是行使在symbol上,symbol中定义的图标(path)会覆盖类名中对应的质量,所以不用忘了安装symbol中元素的性质持续自symbol,如同
    上例中:svg path { fill: inherit; };
  • 5、要想完毕越发复杂的效益,如渐变等,可以行使defs;
  • 6、要想做动画效果,可以在css类名中决定opacity、transform、stroke-dasharray和stroke-dashoffset属性。

2.3 Vector Drawable基本语法

Vector Drawable实际上是一个XML文件,大家先来看一个vector的例子

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="400dp"
    android:height="400dp"
    android:viewportHeight="400"
    android:viewportWidth="400">
    <path
        android:pathData="M 100 100 L 300 100 L 200 300 z"
        android:strokeColor="#000000"
        android:strokeWidth="5"
        android:fillColor="#FF0000"
        />
</vector>

其一vector画了一个三角,对照着方面的代码,大家来学学Vector
Drawable的着力语法。首先说可瑞康(Karicare)下,这个语法开发者不须要全部驾驭,只要可以看懂即可,那一个path标签及数据生卡尔加里可以交到工具来促成。

处理器动画的落实格局

动画片是由一张张图纸组成的,在总计机中,大家称每一张图纸为一帧画面

即使我们想达成如此一个动画片:一个水杯放在桌子的左手,移动到右手,那么大家实际操作的,只是水杯。
为此动画的兑现,只是对移动变化了的有的的拍卖。

俺们一般在处理器上用 FPS ( Frames Per Second) ,即 每秒的帧数
来代表动画的基础代谢速度,基于屏幕的刷新率等其余原因,在处理器上相似选用60 FPS。
一旦运动变化幅度较缓,减半到 30 FPS 时,我们肉眼也是可接受的。
较低的 FPS 会让我们有“卡顿”的痛感。

JS 还有什么用

经过评释属性,调用浏览器来促成的章程,毕竟有限,JS
可以为我们提供极致可能。

透过相比较 CSS3 和 SVG
大家也能看出来,要落成的事物越来越多,大家须要区分、纪念的特性也越来越多。
一个繁杂动画使用注解属性的点子有可能并从未通过编制逻辑来得更爽。看,SVG.js。

在此地倒是想到了 Grunt 和 Gulp 之争
连带琢磨,请过来+关键字#不要给我太多配置项#

css3 属性中扬言的补间效果其实点儿,SVG 的 calcMode,keyTimes,keySplines
又略显复杂,
于是 github 上冒出了一大批补间效果仓库,更有强大者弥补了 CSS3 与 SVG
动画上各种方面的缺少。

5、SVG动画

2.3.1 pathData标签

先看pathData标签,那里定义了vector中path的绘图,也是最重点的一有些。语法如下,注意,’M’处理时,只是活动了画笔,
没有画任何东西。

M = moveto(M X,Y) :将画笔移动到指定的坐标位置,相当于 android Path 里的moveTo()
L = lineto(L X,Y) :画直线到指定的坐标位置,相当于 android Path 里的lineTo()
H = horizontal lineto(H X):画水平线到指定的X坐标位置 
V = vertical lineto(V Y):画垂直线到指定的Y坐标位置 
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次贝赛曲线 
S = smooth curveto(S X2,Y2,ENDX,ENDY) 同样三次贝塞尔曲线,更平滑 
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次贝赛曲线 
T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射 同样二次贝塞尔曲线,更平滑 
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线 ,相当于arcTo()
Z = closepath():关闭路径(会自动绘制链接起点和终点)

逐帧动画和重大帧动画

从帧速率区分动画的话,一般的话大家广大的动画都是属于器重帧动画(Keyframe
Animation)
,而逐帧动画(Frame By
Frame)
是一帧一幅画,从词语来说意味着全片每一秒都是标准24帧逐帧纯手的(在Flash的分别是逐帧动画与动作补间动画,还有分为全动画半动画。)。

差不多介绍一下那多少个概念,想详细询问,可以自取百度如故谷歌(Google)。
动作补间动画:做flash动画时,在三个关键帧中间须求做“补间动画”,才能促成图画的移动;插入补间动画后八个关键帧之间的插补帧是由微机自动运算而赢得的。
全动画:为追求画面完美和动作流畅,依据24帧/s制作动画。
半动画:又名“有限动画”,为追求经济效益,以6帧/s创设动画。

  • 简言之小巧,使用不难
  • 4 大类/29 种补间动画效果
  • 援救 SVG path 路径的补间过渡
    • !稍微有点鸡肋,path 长度不同或项目分歧时出现动画混乱
  • !仅帮衬先河、截止四个状态
animate({ el: "div", // 选择器 duration: 1000, // 执行时间 delay: 0,
// 延迟多少时间开始 easing: "easeOutElastic", // 补间效果 loop:
false, // 是否循环 direction: normal, // 是否重复 begin: function ()
{}, // 开始事件 complete: function () {}, // 结束事件 ...: \['',
''\] // css/SVG 需要改变的属性 });

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6d2831927818175163-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831927818175163-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831927818175163-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831927818175163-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831927818175163-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831927818175163-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831927818175163-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831927818175163-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831927818175163-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831927818175163-10">
10
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831927818175163-11">
11
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6d2831927818175163-1" class="crayon-line">
animate({
</div>
<div id="crayon-5b8f6d2831927818175163-2" class="crayon-line crayon-striped-line">
    el: &quot;div&quot;,  // 选择器
</div>
<div id="crayon-5b8f6d2831927818175163-3" class="crayon-line">
    duration: 1000, // 执行时间
</div>
<div id="crayon-5b8f6d2831927818175163-4" class="crayon-line crayon-striped-line">
    delay: 0,   // 延迟多少时间开始
</div>
<div id="crayon-5b8f6d2831927818175163-5" class="crayon-line">
    easing: &quot;easeOutElastic&quot;,   // 补间效果
</div>
<div id="crayon-5b8f6d2831927818175163-6" class="crayon-line crayon-striped-line">
    loop: false,    // 是否循环
</div>
<div id="crayon-5b8f6d2831927818175163-7" class="crayon-line">
    direction: normal,  // 是否重复
</div>
<div id="crayon-5b8f6d2831927818175163-8" class="crayon-line crayon-striped-line">
    begin: function () {},  // 开始事件
</div>
<div id="crayon-5b8f6d2831927818175163-9" class="crayon-line">
    complete: function () {},   // 结束事件
</div>
<div id="crayon-5b8f6d2831927818175163-10" class="crayon-line crayon-striped-line">
    ...: ['', '']   // css/SVG 需要改变的属性
</div>
<div id="crayon-5b8f6d2831927818175163-11" class="crayon-line">
});
</div>
</div></td>
</tr>
</tbody>
</table>

5.1 路径动画

途径动画基本是svg动画里最常用的了,其基本原理是动态改变stroke-dasharray和stroke-dashoffset属性的值:

亚洲必赢官网 11

实例:

<body>
    <svg>
        <symbol viewBox="0 0 24 20" id="ic" xmlns="http://www.w3.org/2000/svg">
            <title>点赞前</title>
            <path d="M22.825 6.727a6.236 6.236 0 0 0-1.8-3.818A5.275 5.275 0 0 0 17.36 1.44a5.275 5.275 0 0 0-3.667 1.47A11.134 11.134 0 0 0 12 5.09a11.134 11.134 0 0 0-1.692-2.18A5.275 5.275 0 0 0 6.64 1.44a5.275 5.275 0 0 0-3.667 1.47 6.236 6.236 0 0 0-1.8 3.817c-.044.546-.1 2.095 1.236 4.364 2.584 4.364 7.655 6.802 9.59 7.636 1.935-.834 7.006-3.272 9.59-7.636 1.337-2.27 1.28-3.83 1.235-4.364z" stroke="#454545" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" />
    </svg>
    <svg class="icon" viewBox="0 0 100 125">
        <use class="ic-1" xlink:href="#ic" x="0" y="0" />
    </svg>
</body>

    svg.icon {
        width: 120px;
        height: 135px;
    }
    use.ic-1 {
        stroke: gray;
        fill: gray;
        animation: move 3s linear forwards;
    }
    @keyframes move {
        0% {
            stroke-dasharray: 30px, 30px;
        }
        100% {
            stroke-dasharray: 30px, 0px;
        }
    }
    svg path {
        fill: inherit;
        stroke: inherit;
    }

成效就是stroke从30px长和30px空白渐渐变得没有空白

2.3.2 path标签

随着看下path标签的内容。稍微有个影像即可,需求时再对照着去通晓。

android:name 定义该 path 的名字,这样在其他地方可以通过名字来引用这个路径
android:pathData 和 SVG 中 d 元素一样的路径信息。
android:fillColor 定义填充路径的颜色,如果没有定义则不填充路径
android:strokeColor 定义如何绘制路径边框,如果没有定义则不显示边框
android:strokeWidth 定义路径边框的粗细尺寸
android:strokeAlpha 定义路径边框的透明度
android:fillAlpha 定义填充路径颜色的透明度
android:trimPathStart 从路径起始位置截断路径的比率,取值范围从 0 到1
android:trimPathEnd 从路径结束位置截断路径的比率,取值范围从 0 到1
android:trimPathOffset 设置路径截取的范围 
android:strokeLineCap 设置路径线帽的形状,取值为 butt, round, square.
android:strokeLineJoin 设置路径交界处的连接方式,取值为 miter,round,bevel.
android:strokeMiterLimit 设置斜角的上限

逐帧动画

逐帧动画是一种在连年的基本点帧中分解动画动作,即在时光轴的每一帧上绘制差异内容并使之连接播放成动画的一种普遍的卡通格局。

就好像于地点提到的手绘翻页格局,大家得以将以此水杯在每帧画面中的地点一一找出来,那样完成动画的办法就叫作逐帧动画,大家必要处理动画中的每一帧。
逐帧动画是最直接的,但要处理的帧数太多,所以完毕进度是会麻烦。
微机的办事就是来已毕重复单调的劳作的,所以,有些工作是足以考虑让电脑来形成的。

打听更加多关于逐帧动画在电影和动漫上的利用可以点这里

不论是你定义多少补间效果,都满意不断所有人的须求,那里有个 path
路径补间函数生成器。
var myFunc = mojs.easing.path(path),输入一个 SVG path,myFunc()
就是您自己的补间函数。

5.2 SMIL动画(2018/1/1更新)

如上动画格局连接须求借助css来兑现,其实svg专门有做动画的因素
先看运动端兼容性:

亚洲必赢官网 12

SVG SMIL animation

  • set
    在特定时间过后修改某个属性值
    用法:

<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
  <g> 
    <text font-family="microsoft yahei" font-size="120" y="160" x="160">
      马
      <set attributeName="x" attributeType="XML" to="60" begin="3s" />
    </text>
  </g>
</svg>

其一「马」会在3秒将来从横坐标160的岗位移动60以此义务(须臾移,无动画效果)

  • animate
    已毕单属性(不分包css的transform)的卡通片过渡效果

<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
  <g> 
    <text font-family="microsoft yahei" font-size="120" y="160" x="160">
    马
      <animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
    </text>
  </g>
</svg>
  • animateTransform
    专用于transform动画

<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
  <g> 
    <text font-family="microsoft yahei" font-size="80" y="100" x="100">马</text>
    <animateTransform attributeName="transform" begin="0s" dur="3s"  type="scale" from="1" to="1.5" repeatCount="indefinite"/>
  </g>
</svg>
  • animateMotion
    专用于复杂的门径动画

<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
  <text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
    <animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" repeatCount="indefinite"/>
  </text>
  <path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>

2.3.4 vector标签

根元素 vector标签是用来定义那一个矢量图的,该因素包蕴如下属性:

android:name 定义该drawable的名字
android:width 定义该 drawable 的内部(intrinsic)宽度,支持所有 Android 系统支持的尺寸,通常使用 dp
android:height 定义该 drawable 的内部(intrinsic)高度,支持所有 Android 系统支持的尺寸,通常使用 dp
android:viewportWidth 定义矢量图视图的宽度,视图就是矢量图 path 路径数据所绘制的虚拟画布
android:viewportHeight 定义矢量图视图的高度,视图就是矢量图 path 路径数据所绘制的虚拟画布
android:tint 定义该 drawable 的 tint 颜色。默认是没有 tint 颜色的
android:tintMode 定义 tint 颜色的 Porter-Duff blending 模式,默认值为 src_in
android:autoMirrored 设置当系统为 RTL (right-to-left) 布局的时候,是否自动镜像该图片。比如 阿拉伯语。
android:alpha 该图片的透明度属性

重点帧动画

地方的例子,可以改为一个关乎数学和情理的题材:一个杯子开始地点在左手,n秒后匀速运动到右手,那么在每
1/60 秒的时候,这一个杯子的职位显明是足以计算出来的了。
就此,大家实在只必要指定一些 关键
新闻就能让电脑自己总括出每一帧杯子的职位了:

  • 先导地点,比如一个坐标 (0,0)
  • 得了地方,再譬如一个坐标 (100,0)
  • 卡通总时间,比如 0.25 秒
  • 匀速运动

那种措施就叫做关键帧动画。即我们只需求给定多少个关键帧的镜头消息,关键帧与关键帧之间的对接帧都将由微机自动生成。

此间说的 关键帧动画,是指的广义上的一种动画制作方法,并不只指
CAKeyframeAnimation,CABasicAnimation的兑现格局也属于 关键帧动画

  • 太屌,不举行反面评论
  • 最欢跃它的链式操作
var svg = d3.select("\#a") // 选择器 .attr('d',
svg\_num\_path\_d\[0\]) // ... 可以进行其他设置 .attr('fill',
'\#f00') // 设置初始状态 .transition() // 返回 transition 对象
.call(function (transition) { return transition // 承接 transition
对象 .duration(3000) // 执行时间 .delay(0) // 延迟多少时间开始
.ease('cubic-in-out') // 补间效果 .attr('fill', '\#ff0'); //
本次过渡结束状态 }) // 重新返回选择器对象 // ... 可以进行其他设置
.transition() // 进行下一个过渡 .call(function (transition) { return
transition.duration(3000).attr('fill', '\#f0f'); }) // ...
可以进行其他设置 ;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-10">
10
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-11">
11
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-12">
12
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-13">
13
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-14">
14
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-15">
15
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-16">
16
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-17">
17
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831931570115466-18">
18
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831931570115466-19">
19
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6d2831931570115466-1" class="crayon-line">
var svg = d3.select(&quot;#a&quot;)   // 选择器
</div>
<div id="crayon-5b8f6d2831931570115466-2" class="crayon-line crayon-striped-line">
    .attr('d', svg_num_path_d[0])
</div>
<div id="crayon-5b8f6d2831931570115466-3" class="crayon-line">
    // ... 可以进行其他设置
</div>
<div id="crayon-5b8f6d2831931570115466-4" class="crayon-line crayon-striped-line">
    .attr('fill', '#f00')   // 设置初始状态
</div>
<div id="crayon-5b8f6d2831931570115466-5" class="crayon-line">
    .transition()   // 返回 transition 对象
</div>
<div id="crayon-5b8f6d2831931570115466-6" class="crayon-line crayon-striped-line">
    .call(function (transition) {
</div>
<div id="crayon-5b8f6d2831931570115466-7" class="crayon-line">
        return transition   // 承接 transition 对象
</div>
<div id="crayon-5b8f6d2831931570115466-8" class="crayon-line crayon-striped-line">
            .duration(3000) // 执行时间
</div>
<div id="crayon-5b8f6d2831931570115466-9" class="crayon-line">
            .delay(0)   // 延迟多少时间开始
</div>
<div id="crayon-5b8f6d2831931570115466-10" class="crayon-line crayon-striped-line">
            .ease('cubic-in-out')   // 补间效果
</div>
<div id="crayon-5b8f6d2831931570115466-11" class="crayon-line">
            .attr('fill', '#ff0');  // 本次过渡结束状态
</div>
<div id="crayon-5b8f6d2831931570115466-12" class="crayon-line crayon-striped-line">
    })  // 重新返回选择器对象
</div>
<div id="crayon-5b8f6d2831931570115466-13" class="crayon-line">
    // ... 可以进行其他设置
</div>
<div id="crayon-5b8f6d2831931570115466-14" class="crayon-line crayon-striped-line">
    .transition()   // 进行下一个过渡
</div>
<div id="crayon-5b8f6d2831931570115466-15" class="crayon-line">
    .call(function (transition) {
</div>
<div id="crayon-5b8f6d2831931570115466-16" class="crayon-line crayon-striped-line">
        return transition.duration(3000).attr('fill', '#f0f');
</div>
<div id="crayon-5b8f6d2831931570115466-17" class="crayon-line">
    })
</div>
<div id="crayon-5b8f6d2831931570115466-18" class="crayon-line crayon-striped-line">
    // ... 可以进行其他设置
</div>
<div id="crayon-5b8f6d2831931570115466-19" class="crayon-line">
    ;
</div>
</div></td>
</tr>
</tbody>
</table>

5.3 小结

有关用svg做动画,更推荐用5.2的情势,并且5.2中animate的用法是最多的,animate元素还足以组合使用:

<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
    <text font-family="microsoft yahei" font-size="120" y="160" x="160">马
        <animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
        <animate attributeName="opacity" from="1" to="0" begin="0s" dur="3s" repeatCount="indefinite" />
    </text>
</svg>

其它,svg动画还可以够手动控制(JS)动画的上三保太监间断

// svg指当前svg DOM元素
// 暂停
svg.pauseAnimations();

// 重启动
svg.unpauseAnimations()

2.3.5 group标签

突发性大家需求对几个途径一起处理,那样就足以应用 group 元平素把七个 path
放到一起。 group 辅助的属性如下:

android:name 定义 group 的名字
android:rotation 定义该 group 的路径旋转多少度
android:pivotX 定义缩放和旋转该 group 时候的 X 参考点。该值相对于 vector 的 viewport 值来指定的。
android:pivotY 定义缩放和旋转该 group 时候的 Y 参考点。该值相对于 vector 的 viewport 值来指定的。
android:scaleX 定义 X 轴的缩放倍数
android:scaleY 定义 Y 轴的缩放倍数
android:translateX 定义移动 X 轴的位移。相对于 vector 的 viewport 值来指定的。
android:translateY 定义移动 Y 轴的位移。相对于 vector 的 viewport 值来指定的。

透过上边的习性可以看看, group 首如若用来安装路径做动画的显要特性的。

双面的周旋统一

重点帧动画的贯彻方式,只须要修改某个属性值就足以了,不难方便,但关系的深层次内容较多,要求更加多的领会和操练。

动用逐帧动画的落实格局,完结原理简单,但绘制动画的长河要复杂。如果动画进度处理的事务较多,也会拉动较大的付出,就有可能导致动画帧数的低沉,出现卡顿的风貌,因而要求较多的测试和调节。
动画绘制的历程中,会必要较多的数学、物理等学问来计量中间态的数据。

但那三种办法也不是相对分离开的。
重大帧动画落成情势,一般只好对系统已毕了可动画的特性做动画处理,但实际也是同意完结自定义属性的动画片处理的。
那就须求协调来落到实处系统中机动测算过渡帧的操作了,也就是逐帧完毕动画的主意了。

  • 一个和 animateplus 一样容命理术数的框架
  • !大约是因为主打物理引擎(没有讨论,揣测是那样),动画效果有点鸡肋
    • 取名很新颖啊,然则并没有啥卵用
  • 也提供了许多补间效果,还扶助 new ui.Easing(x, y, x, y)
    自定义补间效果

    • !自定义补间仅仅是一个简单易行贝塞尔曲线,和 mojspath-easing
      完全没有可比性啊
  • !多境况的联网是 promise 的写法,完全没有 d3.js 的链式操作来的爽
// 选择器,以及初始状态 var ballActor = new ui.Actor({ element:
'\#ball', values: { backgroundColor: '\#ff2420', borderRadius: '50%'
} }); var morphAnimation = new ui.Tween({ values: { backgroundColor:
'\#2983ff', borderRadius: '0%', x: 300 }, // 结束状态 duration:
1000, // 执行时间 yoyo: true // 相当于 animateplus 的
direction,好奇怪的命名 // flip // loop //
onStart、onFrame、onUpdate、onComplete });
ballActor.start(morphAnimation); // 触发动画

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-10">
10
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-11">
11
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-12">
12
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-13">
13
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-14">
14
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-15">
15
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-16">
16
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-17">
17
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-18">
18
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-19">
19
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-20">
20
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-21">
21
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6d2831936754356035-22">
22
</div>
<div class="crayon-num" data-line="crayon-5b8f6d2831936754356035-23">
23
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6d2831936754356035-1" class="crayon-line">
// 选择器,以及初始状态
</div>
<div id="crayon-5b8f6d2831936754356035-2" class="crayon-line crayon-striped-line">
var ballActor = new ui.Actor({
</div>
<div id="crayon-5b8f6d2831936754356035-3" class="crayon-line">
    element: '#ball',
</div>
<div id="crayon-5b8f6d2831936754356035-4" class="crayon-line crayon-striped-line">
    values: {
</div>
<div id="crayon-5b8f6d2831936754356035-5" class="crayon-line">
        backgroundColor: '#ff2420',
</div>
<div id="crayon-5b8f6d2831936754356035-6" class="crayon-line crayon-striped-line">
        borderRadius: '50%'
</div>
<div id="crayon-5b8f6d2831936754356035-7" class="crayon-line">
    }
</div>
<div id="crayon-5b8f6d2831936754356035-8" class="crayon-line crayon-striped-line">
});
</div>
<div id="crayon-5b8f6d2831936754356035-9" class="crayon-line">
 
</div>
<div id="crayon-5b8f6d2831936754356035-10" class="crayon-line crayon-striped-line">
var morphAnimation = new ui.Tween({
</div>
<div id="crayon-5b8f6d2831936754356035-11" class="crayon-line">
    values: {
</div>
<div id="crayon-5b8f6d2831936754356035-12" class="crayon-line crayon-striped-line">
        backgroundColor: '#2983ff',
</div>
<div id="crayon-5b8f6d2831936754356035-13" class="crayon-line">
        borderRadius: '0%',
</div>
<div id="crayon-5b8f6d2831936754356035-14" class="crayon-line crayon-striped-line">
        x: 300
</div>
<div id="crayon-5b8f6d2831936754356035-15" class="crayon-line">
    },  // 结束状态
</div>
<div id="crayon-5b8f6d2831936754356035-16" class="crayon-line crayon-striped-line">
    duration: 1000, // 执行时间
</div>
<div id="crayon-5b8f6d2831936754356035-17" class="crayon-line">
    yoyo: true  // 相当于 animateplus 的 direction,好奇怪的命名
</div>
<div id="crayon-5b8f6d2831936754356035-18" class="crayon-line crayon-striped-line">
    // flip
</div>
<div id="crayon-5b8f6d2831936754356035-19" class="crayon-line">
    // loop
</div>
<div id="crayon-5b8f6d2831936754356035-20" class="crayon-line crayon-striped-line">
    // onStart、onFrame、onUpdate、onComplete
</div>
<div id="crayon-5b8f6d2831936754356035-21" class="crayon-line">
});
</div>
<div id="crayon-5b8f6d2831936754356035-22" class="crayon-line crayon-striped-line">
 
</div>
<div id="crayon-5b8f6d2831936754356035-23" class="crayon-line">
ballActor.start(morphAnimation);    // 触发动画
</div>
</div></td>
</tr>
</tbody>
</table>

小编将会在此间相比较更加多 JS 动画函数库的施用方法

6、参考:

  • SVG Coca Cola使用简介
  • SVG 探究之路 (18) – 再談
    defs
  • 一级无敌的SVG SMIL
    animation动画详解
  • https://www.nihaoshijie.com.cn/index.php/archives/667/

2.4 一些常用的工具

地点的那么些语法只要能看懂就足以了。大家会用一些成熟的工具来帮助SVG在运动端的开发。

1.先说美工这些最好的工具,SVG图一般直接让美工来帮您搞定就行了!像PS、Illustrator等等都协助导出SVG图片

2.到手到SVG后,大家要将其转移为vector
drawable对象,svg2android其一网站能够帮您轻松落成。

3.比方没有SVG图片怎么做?可以行使SVG的编辑器来进展SVG图像的写作和编辑。

4.赢获得资源后,使用AndroidStudio插件落成SVG添加,AS会自动生成包容性图片(高版本会生成xxx.xml的SVG图片;低版本会自动生成xxx.png图片)。具体进程看Vector
Asset Studio的使用

5.末尾介绍多少个能够获得SVG资源的网站

http://www.shejidaren.com/8000-flat-icons.html
http://www.flaticon.com/
http://www.iconfont.cn/plus

前者高品质动画

何为高品质动画?令人备感流程顺滑即可。24fps的电影就能令人感到到流畅,可是游戏却要60fps以上才能令人感觉到流畅。分析原因,大家得出如下结论:

  1. 摄像的每一帧记录的是一段时间段(1/24s)的新闻,而娱乐的每一帧都由显卡绘制,它只好生成一个时间点的音信;
  2. 视频的帧率是平稳的,而在系统负荷不安定时,显卡很难保障游戏帧率的安定;
    前者动画与娱乐的原理类似,我们安排高品质动画的基本思路就是增进帧率安乐帧率。让我们率先一起驾驭一下浏览器渲染页面的要旨进程。

鸣谢

  • 1 赞 5 收藏 1
    评论

亚洲必赢官网 13

2.5 适配中的一些坑

在正式启幕撸代码前,先解决适配难点。
是因为vector
drawable是5.0过后才出去的事物,所以大家必要对以前的本子举办包容。如若我们都选用Android
Studio
2.2以上的版本,并且gradle版本在2.0之上(应该没有原始人吧)。上面是布署的步骤:

    1.1、添加
·   defaultConfig {
        vectorDrawables.useSupportLibrary = true

    }
    1.2、添加
    compile 'com.android.support:appcompat-v7:25.3.1' //需要是23.2 版本以上的

    1.3、Activity需要继承与AppCompatActivity

    1.4、布局文件当中添加
        xmlns:app="http://schemas.android.com/apk/res-auto"

    1.5、使用在Actvity前面添加一个flag设置
        static {
            AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        }       

Vector Drawable可以了然为一张图片,所以能安装到其余的控件之中。

1 ImageView、ImageButton
XML app:srcCompat(5.0以上可以直接使用background)
代码里面使用无区别,直接setBackground即可。

2. Button 
不支持app:srcCompat
Xm使用在Button的selector中

3. RadioButton 
直接使用

4. textview的drawable  
直接使用

知道浏览器渲染流水线

亚洲必赢官网 ,渲染的中央流程是:扫描HTML文档结构、统计对应的CSS样式并生成RenderTree,然后根据RenderTree举办布局和制图,基本进度示意图如下:

亚洲必赢官网 14

渲染主流程

可以简容易单的叙说为以下四片段:

  1. 解析HTML以构建DOM树
  2. 构建render树
  3. 布局render树
  4. 绘制render树

但实际渲染的进度是那样的:

  1. 在浏览器进行渲染的时候,渲染引擎首先会解析HTML代码,然后将标签转化为DOM树上的一个个相应节点(我们得以在chorme的Elements面板中查看到)。
  2. 继之,渲染引擎解析外部CSS文件及style标签中的样式音讯。那么些样式音信以及HTML中的可知性指令将被用来营造另一棵树—render树。Render树由一些含有有颜色和大小等特性的矩形组成,它们将被按照科学的次第突显到屏幕上。
  3. Render树构建好了将来,将会履行布局进程,它将规定每个节点在显示屏上的熨帖坐标。
  4. 接下来就是绘制,即遍历render树,并采纳UI后端层绘制每个节点。

值得注意的是,那些历程是逐渐完结的,为了更好的用户体验,渲染引擎将会尽可能早的将内容突显到屏幕上,并不会等到具备的html都分析已毕将来再去创设和布局render树。它是分析完部分情节就体现一部分情节,同时,可能还在通过网络下载其余内容。

其余大家应当清楚,在实践某些CSS、JS操作时或者会造成浏览器的回流或者重绘操作,导致浏览器重新渲染页面或者重新绘制页面的某一部分,那么些都是很开支品质的。所以大家在增强动画品质时要客观的考虑那么些元素,尽量收缩渲染或者重绘的次数。

3.Vector Drawable的使用

加强动画品质目标

上文提到过,动画的质量目标有七个,帧率数和帧率稳定性。大家分别从动画完结,节点的拍卖,属性的精选等地点研讨如何增强那三个卡通品质目的。

3.1 Vector Drawable静态使用

整合上文内容,去阿里svg平台无论找张svg的图样,既可以透过svg2android也足以经过AS自带的插件将其转化为vector
drawable,接着布署项目包容环境,再将以此vector在资源xml中用app:srcCompat赋值给ImageView,最后的结果就是这么,无论怎么样放大都不会失真。

考拉.svg

万一您在团结的安卓机上也落到实处了如此的效能,恭喜!关于Vector
Drawable最中央的静态使用已经被您掌控了!

挑选稳定的贯彻方式

css3动画使用起来很是不难,近日的浏览器帮忙率也不利,足以应对一般的互相须要,大家相应事先使用它。当浏览器不帮忙css3时,或动画场景过于复杂而仅凭css3无能为力时,就须求引入js来协助了。我们最常想到的js动画的落到实处形式,就是固定时间距离修改元素的体裁:

setInterval(function(){
    var anmationNode = document.getElementById('animation-node'); 
    //定期修改节点的样式
}, 100);

但这是一种格外狠毒的艺术,其缺点是很鲜明的。浏览器的timer的触发时间点是不定点的,假如碰着比较长的一道义务,其触发时间点就会延迟,鲜明也就保险持续动画帧率的平稳性。HTML5为开创逐帧动画提供了一个新的API:RequestAnimationFrame,该办法在历次浏览器渲染时接触,其触发频率为60fps,大家可以透过那个函数来兑现动画,而当动画中或多或少帧总结量太大不可以在1/60s成就时,浏览器会将刷新评论下落到30fps,以确保帧率的稳定性。

function step(){
    //修改节点样式
    RequestAnimationFrame(step);
}
RequestAnimationFrame(step);

不过由于RequestAnimationFrame扶助程度还不高(手机浏览器普遍不帮衬),我们得以结合RequestAnimationFramesetInterval贯彻一套逐步升高和优雅降级的方案,下边是合营各样浏览器的终极版本:

function getAnimationFrame() {
    if (window.requestAnimationFrame) { 
    //较新浏览器
        return {
            request: requestAnimationFrame,
            cancel: cancelAnimationFrame,
        }
    } else if (window.mozRequestAnimationFrame && window.mozCancelAnimationFrame) {
    //firfox浏览器
        return {
            request: mozRequestAnimationFrame,
            cancel: mozCancelAnimationFrame
        }
    } else if (window.webkitRequestAnimationFrame && webkitRequestAnimationFrame(String)) {
        return {
            request: function(callback) {
                return: window.webkitRequestAnimationFrame(function() {
                    return callback(new Date - 0); 
                    //修正部分webkit版本下没有给callback传time参数的bug
                });
            },
            cancel: window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame
        }
    } else { 

        //用setInterval模拟requestAnimationFrame
        var millisec = 25; //40fps;
        var callbacks = [];
        var id = 0,
            cursor = 0;
        var timerId = null;

        function playAll() {
            var cloned = callbacks.slice(0);
            cursor += callbacks.length;
            callbacks.length = 0;
            var hits = 0;
            for (var i = 0, callback; callback = cloned[i++];) {
                if (callback !== 'cancelled') {
                    callback(new Data - 0);
                    hits++;
                }
            };
            if (hits == cloned.length) {
                clearInterval(timerId);
            }
        }

        timerId = window.setInterval(playAll, millisec);
        return {
            request: function(handler) {
                callbacks.push(handler);
                return id++;
            },
            cancel: function() {
                callbacks[id - cursor] = 'cancelled';
            }
        }
    }
}

3.2 Vector Drawable动态使用

大声告诉我,android中有两种动画的已毕格局?除了帧、补间、属性动画以外,vector
drawable也足以用来已毕动画效果,还记得在此以前讲的path标签呢,这中间的性质都足以当做动画的转变条件,大家再突显一下:

android:name 定义该 path 的名字,这样在其他地方可以通过名字来引用这个路径
android:pathData 和 SVG 中 d 元素一样的路径信息。
android:fillColor 定义填充路径的颜色,如果没有定义则不填充路径
android:strokeColor 定义如何绘制路径边框,如果没有定义则不显示边框
android:strokeWidth 定义路径边框的粗细尺寸
android:strokeAlpha 定义路径边框的透明度
android:fillAlpha 定义填充路径颜色的透明度
android:trimPathStart 从路径起始位置截断路径的比率,取值范围从 0 到1
android:trimPathEnd 从路径结束位置截断路径的比率,取值范围从 0 到1
android:trimPathOffset 设置路径截取的范围 
android:strokeLineCap 设置路径线帽的形状,取值为 butt, round, square.
android:strokeLineJoin 设置路径交界处的连接方式,取值为 miter,round,bevel.
android:strokeMiterLimit 设置斜角的上限

结余就是满满的套路了。
先是,获取到一张vector图片,比如本次使用的是一个对勾。大家给path标签附上了name属性,这是为着未来在动画中找到那条path。

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:name="path_check"
        android:fillColor="#FF000000"
        android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

随后,用动画vector包装原来的vector图片,其创造形式和vector相似,只可是最外层的价签为animated-vector。我们还要为target标签赋值,name属性是眼前命名的、vector中须要转移的地点,而animation自然就是性质动画了。

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
                 android:drawable="@drawable/ic_done_black_24dp">
    <target
        android:name="path_check"
        android:animation="@animator/check_animator"/>
</animated-vector>

到底照旧必要用到属性动画,大家透过xml的不二法门来成功它。注意要在res下创制animator文件夹,再将xml放入其中。那里变化的质量是path标签中trimPathEnd属性。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
    android:duration="500"
    android:propertyName="trimPathEnd"
    android:valueFrom="0"
    android:valueTo="1"
    android:valueType="floatType"/>
</set>

终极,只要在代码大校Drawable转化为Animatable,并调用其start()办法开启动画即可。

  <ImageView
        android:id="@+id/iv"
        android:layout_width="240dp"
        android:layout_height="240dp"
        app:srcCompat="@drawable/check_animator"
        />

 imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Animatable animatable = (Animatable) imageView.getDrawable();
                animatable.start();
            }
        });

来看望效果图吧

动态vector.gif

为动画节点创造新的渲染层

因此将动画节点与文档中的其他节点隔离开来,可以使得的滑坡重复布局(relayout)和重新绘制(repaint)的面积,从而增强页面的一体化品质。隔离动画节点与文档中的其他节点方法一般是为动画片节点创立新的渲染层(render
layer)。下边是开创渲染层的常用方法:

4.交互式中国地图

大家曾经了然了静态与动态的SVG使用,接下去要学习更具挑衅性的交互式应用。原图长那样:

中华地图.svg

大家要完结的成效就是每个省份都能被点击并彰显出来。很明显,这么一个叶影参差的图纸是android中其余的知识所不能解决的。先看看效果图

2017-10-27_12_13_27.gif

上面分析思路。首先,解析SVG图片,由于每个省份都是一个path,因而可以取获得34个Path。又因为每个省份都有例外的颜料、被点击时有不一致的绘图方式,所以能够创立provinceItem对象来封装那一个参数和措施。最后是点击事件的主宰与判断,倘若当前触摸点在某个省份内,就将其大约杰出。

使用3D变换

世家肯定日常来看网上的小说说利用transform: translate3d(0, 0, 0)/translateZ(0)(详细询问点击那里)可以开启GPU加快,亲自试验之后发现其真正可以升高页面的渲染速度,我就曾经用它解决了一部分低端机的闪耀难点。
那么其规律是怎样呢?这种方法并非一定可以打开GPU加快。

W3C标准是如此说的。

Three-dimensional transforms can result in transformation matrices
with a non-zero Z component (where the Z axis projects out of the
plane of the screen). This can result in an element rendering on a
different plane than that of its containing block. This may affect the
front-to-back rendering order of that element relative to other
elements, as well as causing it to intersect with other elements.

其主要意思就是3D变换会创立新的渲染层,而不是与其父节点在同一个渲染层中。在新的渲染层中修改节点不会干扰到其余节点,防止了对其它节点的再度布局(relayout)和重复绘制(repaint),自然也就加速了页面的渲染速度。除了transform:
translate3d(0, 0, 0)/translateZ(0),大家还足以应用will-change。

4.1 ProvinceItem

俺们以小博大,先从ProvinceItem对象初始介绍。该目的有2个参数,分别是从SVG中分析出来的path以及该path必要填写的水彩color。每个“省”都提供了绘图方法,用来让外部的地形图控件调用,以此绘制普通状态或者选中状态。

  /**
     * 是否被选择
     *
     * @param canvas
     * @param paint
     * @param isSelected
     */
    public void draw(Canvas canvas, Paint paint, boolean isSelected) {
        if (isSelected) {
            paint.setStrokeWidth(3);
            paint.setColor(Color.BLACK);
        }else {
            paint.setStrokeWidth(1);
            paint.setColor(0xFFD0E8F4);
        }
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(path,paint);

        paint.setColor(drawColor);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawPath(path, paint);
    }

平常状态和当选状态的分化只是外表概况的颜色和粗细,使用paint分别绘制其大约和填充颜色即可。

重中之重在于判断触摸点是不是在某个省的限制内。每个省都是狼狈的图形,说到不平整,是还是不是想起此前讲Canvas时介绍的Region?Region代表一块区域,其面积的盘算是应用微积分的原理,正好在此派上用场。

  public boolean isTouch(int x, int y) {
        RectF rectF=new RectF();
        path.computeBounds(rectF,true);
        Region region=new Region();
        region.setPath(path,new Region((int)rectF.left,(int)rectF.top,(int)rectF.right,(int)rectF.bottom));
        return region.contains(x,y);
    }

无论是多么不平整的图片,总会有极限的上下左右,大家因而path.computeBounds()计量出这几个上下左右的界限,再通过region.setPath()将path和内外左右不翼而飞,即可获得path所对应的那块region。

使用will-change

我们得以行使will-change让浏览器提前打探预期的因素变换,它同意浏览器提前做好方便的优化,使之最后可以飞快和流畅的渲染。will-change:
transform同样也会为节点创建新的渲染层。

.animation-element{
     will-change: transform;
}

4.2 MapView

上边介绍外层的地图控件MapView,在早先化方法中,loadThread用来从SVG中加载数据,GestureDetectorCompat用来代理onTounch()中的触摸事件,没什么多余的情趣,就是简单不用谢swich语句而已……

    private void init(Context context) {
        this.mContext = context;
        mProvinceItems = new ArrayList<>();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        loadThread.start();
        mGestureDetectorCompat = new GestureDetectorCompat(mContext, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                handleTouch(e.getX(), e.getY());
                return true;
            }
        });

    }

先看在子线程中加载数据的操作,由于svg是以xml的花样表现的,所以先要解析xml。这里运用了dom解析,当然你欣赏sax或者pull或者其余什么都无所谓。

Thread loadThread = new Thread() {
        @Override
        public void run() {
            List<ProvinceItem> items = new ArrayList<>();//用新的list防止加载时冲突导致crash
            InputStream inputStream = mContext.getResources().openRawResource(R.raw.map_china);
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            try {
                DocumentBuilder builder = factory.newDocumentBuilder();
                Document doc = builder.parse(inputStream);
                Element root = doc.getDocumentElement();
                NodeList list = root.getElementsByTagName("path");
                for (int i = 0; i < list.getLength(); i++) {
                    Element element = (Element) list.item(i);
                    String pathData = element.getAttribute("android:pathData");
                    Path path = PathParser.createPathFromPathData(pathData);
                    ProvinceItem item = new ProvinceItem(path);
                    items.add(item);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            mProvinceItems = items;
            mHandler.sendEmptyMessage(1);
        }
    };

这段代码的主要其实际PathParser.createPathFromPathData(pathData)那行,其效能是将vector
drawable中的path语法转化为android中的Path类。这不是一件简单的生意,但那又是一件须求很普遍的饭碗,所以自己选拔采纳开源的类比如CSDN上就部分下载,那里限于篇幅我只把那么些点子单独拉出去溜溜,有趣味的同室去找个工具类自己学习啊:

 public static Path createPathFromPathData(String pathData) {
        Path path = new Path();
        PathDataNode[] nodes = createNodesFromPathData(pathData);
        if (nodes != null) {
            try {
                PathDataNode.nodesToPath(nodes, path);
            } catch (RuntimeException e) {
                throw new RuntimeException("Error in parsing " + pathData, e);
            }
            return path;
        }
        return null;
    }

回到大家的代码中,loadThread在结尾给handler发送了音讯,handler成效很简短,只是给分裂的path随机赋予颜色值

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (mProvinceItems == null) {
                return;
            }
            int totalNumber = mProvinceItems.size();
            for (int i = 0; i < totalNumber; i++) {
                int color;
                int flag = i % 4;
                switch (flag) {
                    case 1:
                        color = colorArray[1];
                        break;
                    case 2:
                        color = colorArray[2];
                        break;
                    case 3:
                        color = colorArray[3];
                        break;
                    default:
                        color = colorArray[0];
                        break;
                }
                mProvinceItems.get(i).setDrawColor(color);

            }
            postInvalidate();
        }
    };

handler的最后,postInvalidate()会造成重绘,进而调用onDraw()方法。那里又提到到scale放大倍数,由于svg本身的亮点就是随便拉伸,因而予以MapView控件那个scale属性是自然的。剩下就是各自绘制普通省份和被入选省份。

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mProvinceItems != null) {
            //放大倍数
            canvas.scale(scale, scale);
            for (ProvinceItem item : mProvinceItems) {
                if (item != selectedItem) {     
                    item.draw(canvas, mPaint, false);
                }
            }
            if (selectedItem != null) {
                selectedItem.draw(canvas, mPaint, true);
            }
        }
    }

最终来看望触摸事件,onTouchEvent中一向回调mGestureDetectorCompat的方式。

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mGestureDetectorCompat.onTouchEvent(event);
    }

此地为了为难封装了下

mGestureDetectorCompat = new GestureDetectorCompat(mContext, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                handleTouch(e.getX(), e.getY());
                return true;
            }
        });

末了一个第一,由于事先的canvas拉伸过,所以在处理点击位置时索要恢复生机。

  private void handleTouch(float x, float y) {
        if (mProvinceItems == null) {
            return;
        }
        ProvinceItem tmpItem = null;
        for (ProvinceItem item : mProvinceItems) {
            if (item.isTouch((int) (x / scale), (int) (y / scale))) {
                tmpItem = item;
                break;
            }
        }
        if (tmpItem != null) {
            selectedItem = tmpItem;
            postInvalidate();
        }
    }

采取高效的动画属性

修改节点的多数属性都会引起重新绘制,甚至是再一次布局。而优异状态下,大家应幸免再一次绘制和重新布局。幸运的当仅仅修改transfrom属性或opacity属性,可以成功不另行绘制。具体的笔触是:为急需创立动画的节点创立新的渲染层,并且在新渲染层中只修改transformopacity属性。唯有形成以上两点才方可幸免再度布局和再一次绘制,真正使用GPU加快。

5.总结

代码分析落成,是或不是还挺不难的?其实最难的局地美工已经帮大家解决了,大家如若解析SVG获取到对应的属性,在通过path啊,paint啊之流去处理那个属性,就足以轻松的已毕部分繁杂的自定义控件了。

末尾祝我们不会被美工分而食之!

防止引起多余的渲染

大家在落到实处动画的进度中,日常索要得到某个元素的特性,然后对该属性做出修改:

function step(){
    var animationNode = doucment.getElementById('animation-node');
    for(var i = 1; i <= 20 ; i++){
        animationNode.width = animationNode.width + 1;
    }
}

上述的for循环语句将促成浏览器举办20次剩余的渲染,严重影响页面质量。平常来讲JS对页面样式的累累改动只会在页面下次刷新时渲染一遍,而因此DOM
API获取样式时,会强制页面完毕一次渲染以展现最新修改后的值。上述例子就是那样造成浏览器多次渲染的。而正确的写法应该是读写分离。

var animationNode = doucment.getElementById('animation-node');
var initialWidth = animationNode.style.width;
for(var i = 1; i <= 20 ; i++){
    initialWidth+=1;
}
animationNode.style.width = initialWidth; 

当大家在千丝万缕页面上贯彻动画是,经常由于疏忽造成页面多余的渲染。那是大家得以借助fastdom来隔断对真实DOM的操作,fastdom将对节点样式的读写批量缓存、两回施行,幸免多余的渲染。

参照资源

  1. 简书作者/胖花花的剖析 iOS
    动画原理与贯彻
  2. 逐帧动画和根本帧动画
  3. 前端高质量动画最佳实践

正文只是将互联网上对动画系统和布置前端的动画方面做了大概的重组。
其中在前端高质量动画最佳实践一文中的底部有几篇参考资料格外的好,对于了解前端动画有很好的增援,推荐一下:

  1. 前端动画原理与完成,那篇作品通过PPT的章程介绍了前者动画,页面做的科学。
  2. How browsers
    work,那篇小说介绍了浏览器的做事规律和流程,对于想深刻明白浏览器工作原理和流程的同窗可以一试。
  3. Javascript高品质动画与页面渲染,那篇小说和前端高品质动画最佳实践同样,只不过是对于前端动画的另一个角度的解读,并且可能更详尽。
网站地图xml地图