关于animation:关于Addressable打包图集与图片都打进去造成冗余

1)对于Addressable打包图集与图片都打进去造成冗余2)Unity如何计算Root动画旋转3)IL2CPP编译的Protobuf反射类运行时报空4)为什么Active Constraints会呈现过高的景象 这是第337篇UWA技术常识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地把握和学习。 UWA社区主页:community.uwa4d.comUWA QQ群:465082844 AddressableQ:对于Addressable打包图集与图片都打进去造成冗余。 Unity版本:2021.2.13f1c1Addressable版本:1.19.16(cn版本) 应用的是Addressable的默认Group,场景中只应用了decal3的UI图片,然而打包最初的资源,Addressable的包中蕴含了两个资源,失常应该只有图集资源才对(如下图)。 另外,看了Addressable打包流程的代码,Unity把关联的图片退出依赖打包列表,然而又在之后对图片检测做了生成图集的解决。原生打包不会对图集里的图片再做解决吗? A:能够切换com.unity.ScriptableBuildPipeline版本到1.21.5试试看,1.21.5修复的问题应该包含这个。更新日志:https://docs.unity3d.com/Packages/com.unity.scriptablebuildpi...感激liuxianfeng@UWA问答社区提供了答复 AnimationQ:想理解Unity的RootMotion的实现细节,请问Unity是怎么计算Root动画旋转的? 一个动画,如果配置正确,AnimationClip里会多两段曲线数据,RootT、RootQ别离是根节点的位移和旋转信息。然而当我用Animator跑起来后,咱们每帧RootMotion旋转多少,Root节点逆向旋转多少,是怎么计算出来的呢? 奢侈的想法是:旋转以后帧的RootQ绝对于第0帧RootQ的旋转的eulerAngles.y。然而通过我屡次测试,并不是这个值,而是有偏差的一个值。有时候多几度,有时候少几度。 没有Unity源码的状况下,很难晓得它的计算方法。我去看了Godot,其办法是失常把以后旋转和第0帧做差值。 比方这个动画,我曾经把数据删得差不多了。第1帧,Animator认为应该转24.068,这两个旋转的欧拉角示意别离是(277.77, 66.96, 81.36) 、(279.53, 74.28, 100.03),from to旋转的欧拉角是(3.29, 25.78, 0.02) 。这个25.78和24差得不多,然而总归不一样。其余测试数据相似,都是差一点。 A:对于旋转的计算,Unity应用了四元数(Quaternions)来示意旋转。旋转的差别可能是因为以下起因之一导致的: 欧拉角(Euler angles)转换为四元数的过程中可能存在精度损失。欧拉角存在万向锁问题和旋转程序问题,这可能导致从欧拉角转换为四元数时呈现不精确的后果。根节点旋转的计算可能受到其余因素的影响,例如动画过程中的插值算法、关键帧的设置、平滑过渡等。这些因素可能会导致计算结果与冀望的差别。感激NG週@UWA问答社区提供了答复 ScriptQ:IL2CPP编译的Protobuf反射类运行时报空,问题产生时,会闪崩,闪崩日志信息:ErrorNotNull:"c# exception:System.TypeInitializationException: The type initializer for 'abcConfigReflection' threw an exception. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ExecutionEngineException: Attempting to call method 'Google.Protobuf.Reflection.ReflectionUtil+ReflectionHelper`2[[System.IntPtr&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated.n ...

May 30, 2023 · 2 min · jiezi

关于animation:在UI上制作动画的方案选择

1)在UI上制作动画的计划抉择2)AssetBundle依赖加载问题3)TTF字体如何渲染未蕴含的字符4)Unity 2020.3 应用HDRP渲染管线启动我的项目很卡 这是第278篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) AnimationQ:在UI上做动画是应用Animation还是Animator呢?或者有什么更好的计划吗? A:之前专门对这个问题做过测试,在场景中用3种办法实现同样的动画。 复制10份和50份同样的动画,测试数据如下: 从耗时上看,Dotween是最优的,所以对于比较简单的动画,倡议尽量应用Dotween来实现。 感激Xuan@UWA问答社区提供了答复 AssetBundleQ:对于AssetBundle依赖加载的问题,比方一个公共资源A,有很多(B、C、D、E…)Bundle都援用了A。实践上是先加载公共资源A,再加载(B、C、D、E…),然而在不同中央可能(B、C、D、E…)会同时加载,那么A是不是加载了很屡次,这种状况是要如何解决呢? A1:B、C、D、E筹备加载A时,如果发现A已加载就跳过,加载中就追加一个回调,未加载才须要触发加载A。感激黄晓文@UWA问答社区提供了答复 A2:曾经加载过的Bundle要记录下来:Dictionary<string,AssetBundle>,那么天然曾经加载过的AssetBundle就不必再加载。 另外AssetBundle还要做援用计数,援用为0就Unload,不懂就看Addressable的源码。 感激Jee@UWA问答社区提供了答复 A3:Unity的AssetBundle治理其实还是须要本人去手动做。如果一个AssetBundle被反复加载,那么引擎会间接报错。所以就像楼上说的,搞一个数据结构和容器通过援用计数去全程跟踪记录AssetBundle的加载及应用情况。感激黄程@UWA问答社区提供了答复 FontQ:一些TTF字体,其中只蕴含了英文数字标点等无限的几百个字符,当我用这个字体显示中文的时候,能够显示,单并不是字体的格调,他是如何做到的?Fallback到其余零碎默认字体吗? A:能够浏览一下官网文档,有比拟具体的阐明:https://docs.unity3d.com/Manu... “When Unity tries to render text with a dynamic font, but it cannot find the font (because Include Font Data was not selected, and the font is not installed on the user machine), or the font does not include the requested glyph (like when trying to render text in east Asian scripts using a latin font, or when using styled bold/italic text), then it will try each of the fonts listed in the Font Names field, to see if it can find a font matching the font name in the project (with font data included) or installed on the user machine which has the requested glyph. If none of the listed fallback fonts are present and have the requested glyph, Unity will fall back to a hard-coded global list of fallback fonts, which contains various international fonts commonly installed on the current runtime platform.” ...

December 15, 2021 · 1 min · jiezi

关于animation:htmlcss画呼吸灯

搞不了视频太难了。。。。 Animations是css3的一个模块,应用keyframes定义如何随着工夫的挪动扭转CSS的属性值,能够通过指定它们的持续时间,反复次数,如何反复来管制关键帧的行为。Animations由两局部组成:css动画的配置,以及一系列的keyframes(用来形容动画的开始、过程、完结状态) transform 属性向元素利用从2D或3D转换。该属性容许咱们对元素进行旋转、缩放、挪动或者歪斜 <!-- * @Author: [you name] * @Date: 2021-08-12 17:00:29 * @LastEditors: [you name] * @LastEditTime: 2021-09-16 22:27:09 * @Description: 呼吸灯的实现 用transform和animation实现--><!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .bg { width: 500px; height: 500px; margin: 50px auto; background-color: rgb(217, 255, 2); position: relative; } .bg .small_cirlce { width: 300px; height: 300px; border: 20px solid white; /* 程度居中 */ top: 50%; left: 50%; margin-top: -150px; margin-left: -150px; position: absolute; /* 变成边框盒子 它的宽高是整个盒子的宽高 */ /* 因为边框占据了40px 所以用内容盒子的话会使其不能居中 所以要转换成边框盒子 */ box-sizing: border-box; border-radius: 50%; /* 设置动画 自定义动画名称circle ease-in-out:动画以低速开始和完结 infinite示意有限次执行*/ animation: circle 5s ease-in-out infinite; } .bg .big_circle { width: 400px; height: 400px; border: 10px solid white; /* 设置程度居中 */ top: 50%; left: 50%; margin-top: -200px; margin-left: -200px; position: absolute; /* 变成边框盒子 它的宽高是整个盒子的宽高 */ /* 因为边框占据了20px 所以用内容盒子的话会使其不能居中 所以要转换成边框盒子 */ box-sizing: border-box; border-radius: 50%; /* 设置动画 自定义动画名称circle ease-in-out 动画以低速开始和完结 infinite:有限次执行*/ animation: circle 5s ease-in-out infinite; } /* 设置动画 */ @keyframes circle { /* transform 属性向元素利用从2D或3D转换。该属性容许咱们对元素进行旋转、缩放、挪动或者歪斜 */ 0% { /* 扭转大小 缩放 scale */ transform: scale(0.6); border-color: rgb(255, 3, 3); } 25% { /* 扭转大小 */ transform: scale(0.7); border-color: rgb(243, 5, 183); } 50% { /* 扭转大小 */ transform: scale(0.8); border-color: rgb(5, 101, 245); } 75% { /* 扭转大小 */ transform: scale(0.9); border-color: rgb(77, 248, 10); } 100% { /* 扭转大小 */ transform: scale(1); border-color: rgb(2, 236, 244); } } </style></head><body> <div class="bg"> <div class="small_cirlce"></div> <div class="big_circle"></div> </div></body></html> ...

September 16, 2021 · 2 min · jiezi

关于animation:实现多个元素的css动画同时执行

css动画是队列式的,以后一个动画执行完才会执行下一个动画,也就是你删除了动画类名,认为革除了动画,其实只是将动画暂停而已,想要动画每次都是从新开始的解决办法是,在css里再写一个截然不同的动画,两个动画类名来回切换就能每次从新开始了,比方: <template> <div> <div v-for="(item,index) in list" :key="index" :class="[active===index?'':show?'changeColor':'changeColor2']" @click="changeColor(index)">色彩</div> </div></template><script> export default{ name:"color", data(){ return { list:[ {name:"a"}, {name:"b"}, {name:"c"} ], show:true, active:0 } } methods:{ changeColor(){ this.active=index; this.show=!this.show } } }</script><style>@keyframes colors { 0%{ color: red } 100% { color: yellow } }@keyframes colors2 { 0%{ color: red } 100% { color: yellow } } .changeColor { animation:colors 5s linear 0s infinite; -webkit-animation:colors 5s linear 0s infinite; } .changeColor2 { animation:colors2 5s linear 0s infinite; -webkit-animation:colors2 5s linear 0s infinite; }</style>

July 29, 2021 · 1 min · jiezi

关于animation:自如大前端web动画探索一

前端我的项目直面客户,为了更好的交互体验,免不了须要应用动画来增香提味。在此分享自若动画的尝试与摸索。 一、简略的过渡成果transition应用transition实现:位移、旋转、缩放、透明度等简略过渡成果。 长处:晦涩、简略。 毛病:仅能实现简略动画,仅能监控动画完结(transitionend),无奈实现用户交互。 transitionend(完结)事件监控:<template> <div class="box1" ref="box1" :class="{move: isMove}" @click="isMove=!isMove"></div></template><script lang="tsx">import { Component, Vue } from 'vue-property-decorator';@Component({ name: 'index' })export default class Index extends Vue { private isMove: boolean = false; private transitions: any = { 'transition':['transitionend'], 'OTransition':['otransitionend'], 'MozTransition':['mozTransitionEnd'], 'WebkitTransition':['webkitTransitionEnd'] }; mounted(){ let _style = (this.$refs.box1 as any).style; for(let t in this.transitions){ if( _style[t] !== undefined ){ this.transitions[t].map((element:string)=>{ (this.$refs.box1 as any).addEventListener(element, ()=>{this.callBack(element)}, false); }); } } } callBack(type:string){ // do something console.log(type); // transitionend }}</script><style lang="scss" scoped>.box1{ width: 100px; height: 100px; background: #999; transition: all 0.5s; &.move{ transform: translateX(100px); }}</style>二、逐帧动画动画的速度曲线 animation-timing-function : ...

February 3, 2021 · 4 min · jiezi

关于animation:带BlendShape表情的动作文件播放异常

1)带BlendShape表情的动作文件播放异样2)Unreal打包Android我的项目的报错3)Unreal打包Android我的项目前,执行SetupAndroid.bat脚本报错4)Addressable打包Post Processing产生冗余5)Addressable资源热更新,提醒CRC Mismatch 这是第229篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) AnimationQ:从Maya中导出一个带表情的动作,动作能够失常播放,然而表情不能播放,请问这是为什么?在FBX导入设置窗口,表情是能看到的,然而放到场景里却看不到。能够看到动画节点,但所有的BS节点都显示Missing。 A:Maya的表情动画,间接在Unity里播放不进去。我拆散到Animation,而后用一个插件,从新绑定BS节点,就能够播放了。可参考以下网址:https://github.com/chr33z/unity-blendshape-mapper感激题主韩飞@UWA问答社区提供了答复 EditorQ:Unreal打包Android我的项目,报错如下图所示,请问是什么起因? 具体报错可参见原问答。 A:提供以下解决方案,亲测无效:Unreal我的项目打包进行环境配置的时候,在对应模块的.Build.cs文件中,要增加对应代码:PublicAdditionalLibraries.Add(Path.Combine(externalLib, “Android/armeabi-arm64/liblua.a”));PublicAdditionalLibraries.Add(Path.Combine(externalLib, “Android/armeabi-v7a/liblua.a”));PublicAdditionalLibraries.Add(Path.Combine(externalLib, “Android/x86/liblua.a”)); 但如果打包的我的项目,不产生的我的项目要移除对应的代码。例如只打包armv7的我的项目,就要移除x86和arm64对应的代码。 该问答由UWA提供 EditorQ:Unreal打包Android我的项目前,配置环境下执行SetupAndroid.bat脚本遇到“此时不应有Microsoft”的报错,请问是什么起因? A:在PATH环境变量中删除含有Microsoft字段的门路即可,可参考:https://answers.unrealengine.com/questions/963972/view.html该问答由UWA提供 AddressableQ:有多个摄像机的Prefab,每个摄像机都挂了后处理,Prefab都调配了Addressable地址。运行Analyze Rules后没有显示PostProcess资源有冗余,导致打包进去每个Prefab都挂了Package外面的资源。 应用版本如下:Unity 2018.4.27Postprocess 2.30Addressables 1.16.1 A:通过测试,Addressable 1.15.1版本,应用Analyze工具是能够检测进去冗余的,用1.16.1就不行,前面的1.16.10也不行,不晓得Addressable批改了什么,比对了1.15.1和1.16.1的代码,没看进去是什么导致的。感激Xuan@UWA问答社区提供了答复 AddressableQ:Addressable资源热更,提醒CRC Mismatch问题,将须要热更的资源曾经上传至CDN对应目录,启动游戏报错如下,不晓得什么问题,大家有遇到吗? A:曾经解决,按官网解决形式,先禁用。感激题主在路上哈哈@UWA问答社区提供了答复 封面图起源:Vox BlendUnity的BlendShape控制器插件。 明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。 官网:www.uwa4d.com官网技术博客:blog.uwa4d.com官网问答社区:answer.uwa4d.comUWA学堂:edu.uwa4d.com官网技术QQ群:793972859(原群已满员)

December 15, 2020 · 1 min · jiezi

关于animation:使用SBP后如何查询Bundle的依赖关系

1)应用SBP后,如何查问Bundle的依赖关系2)大量同样的怪物的骨骼动画如何优化3)DynamicBone动静骨骼插件是否在我的项目里应用4)音频换Wwise的老本5)运行时如何保留Prefab 这是第225篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) AssetBundleQ:应用ContentPipeline.BuildAssetBundles接口打出Bundle文件后,没有产生AssetBundleManifest文件,请问该如何查问某个Bundle所依赖的其余Bundle呢? A:能够从ComatibilityBuildPipeline.cs的源码外面看到上面的代码, 用上图中的办法来生成Manifest对象,而后参考《应用SBP打Bundle如何读取AssetBundleManifest》生成资源文件和打包AssetBundle。 感激Xuan@UWA问答社区提供了答复 AnimationQ:大量同样的怪物的骨骼动画应该怎么优化? 1.如果有N个怪物,是否同样的骨骼动画会计算N遍来失去每个Mesh的新的顶点地位。2.如果1是对的,是否计算完一个怪物在动画这一帧的顶点地位后,其余怪物都用这个计算好的后果进行渲染。 第二个问题的这个办法我认为是和GPU Instancing的贴图动画是有区别的。不晓得第二个办法有没有实现的可能,或者曾经有人实现了吗? 就是这一群模型体现都一样,变换矩阵每一帧都一样。请问Shared SkinnedMesh计划是什么思路,或者有没有参考链接? A:请参考以下答案:1.不同模型的动画序列帧不同,骨骼的变换矩阵必然有差别,除非这一群模型体现都一样,能够本人写一套Shared SkinnedMesh的计划。如果须要在CPU端蒙皮把Shader中的蒙皮计算拿进去就好。 Shared SkinnedMesh的计划参考:https://lab.uwa4d.com/lab/5bc6f85504617c5805d4eb0a 2.GPU Instancing的计划也是通过将序列帧骨骼动画烘培到贴图中,而后在顶点着色器中实现蒙皮计算的过程。 具体细节可参考:《移动游戏开发核心技术解说:3D UI、GPU Skinning和DOTS》中GPUSkinning相干内容。 感激羽飞@UWA问答社区提供了答复 AnimationQ:DynamicBone动静骨骼插件有人测试过性能吗?是否倡议在我的项目里应用? A1:这插件的性能真费,我的项目里配角30根骨骼用上这个插件后,高端机每帧耗时1ms。2集体就是2ms了。感激剑影蒙残@UWA问答社区提供了答复 A2:能够用,然而不能大面积用,最好用在重点对象上,适宜搞一些骚操作。感激与我相干@UWA问答社区提供了答复 A3:齐全能够应用。咱们上一个我的项目中有大量的舞蹈动作,最多反对16人的同台表演。在服装制作上应用了和DynamicBone相似的Unity日本开源的UnityChan中的SpringBone。同时进行了魔改,退出了横向束缚避免在抬腿等大幅度动作时的穿模。魔改后的版本计算量比原版更大。 这类弹簧骨骼零碎的计算量次要在两方面,一方面是计算弹簧间的力传导,另一方面是计算碰撞,都是重CPU的计算,是非常适合放入子线程去做的。刚好能够利用Unity的ECS来进行优化。 目前网上开源的实现中,能够参考下https://github.com/EsProgram/uSpringBone的实现。但因为ECS目前还未正式Release,所以稳定性不是特地好。 前段时间在逛AssetStore时,发现一个新的插件,应用JobSystem+BurstCompiler,举荐你们去看看。 MagicaCloth 感激范君@UWA问答社区提供了答复 AudioQ:咱们当初Unity原生的音频,应用的是一个Resonance-Audio插件,可能咱们本人也没用好,但能凑合着用。 据说Wwise不错,打算都换上。但昨天下载了一天没装置上,而且和现有音频不能一起用,不知大家是否也遇到过这样的问题,有没有什么好的思路? 大家在我的项目中途转Wwise的老本大吗? A1:咱们也转了Wwise,与原生的确不能共用。须要把现有的音频放到Wwise工程之后,再分平台对立导出,Wwise导入导出以及治理还是蛮不便的。装置也是装了两三遍才装完。Wwise Launcher软件和Unity Intergration仿佛是分两次下的,集成入Unity工程须要等那个页面反馈一下,否则一不小心又会点到下载。 问题的确在装置,设置,打包,打热更都会有一点。 链接里是我碰到过的几个问题,尽管不是很全,能够参考看看:https://kmageek.com/2020/06/23/wwiseUnity/ 感激Maggie@UWA问答社区提供了答复 A2:做好音频文件和我的项目工程的解耦(音频播放配表,不是通过Prefab关联),转过去会很不便,Wwise通过Bank加载、ID播放,做好ID和音频名称的映射。个别会进行二次开发,在Editor做个Bank解析、播放、关联的小标签会不便策动配置。感激郑骁@UWA问答社区提供了答复 ScriptQ:运行时代码克隆了一个Prefab,而后我改了坐标或者角度,如何再保留回Prefab? 我这个保留的数据只是举了简略的例子,理论是运行时美术会改特效特效Particle system外面一堆参数的。 A1:倡议应用ScriptableObject来实现相干性能。不同对象的参数调整要离开思考。如果是粒子系统,编辑模式下根本都能够调了。大部分参数在编辑模式下调好,十分大量的能够在运行模式下调。调好后拷贝一下,而后退回编辑模式粘贴一下应该也能够了。 当然也能够把一些参数提出到ScriptableObject,调这个序列化,每次运行启动的时候赋值给指标对象。如果有必要也能够做个按钮,运行时按后间接去批改Prefab内的值,只是这样解决起来比拟麻烦。不是很大很简单的需要还是尽量避免。 其余的一些Prefab内编辑器模式下不不便调的,还是倡议提出到ScriptableObject来解决更好。 感激黄程@UWA问答社区提供了答复 A2:PrefabUtility.SaveAsPrefabAssetAndConnect感激与我相干@UWA问答社区提供了答复 封面图来源于网络 明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。 官网:www.uwa4d.com官网技术博客:blog.uwa4d.com官网问答社区:answer.uwa4d.comUWA学堂:edu.uwa4d.com官网技术QQ群:793972859(原群已满员)

November 5, 2020 · 1 min · jiezi

译Vue-svg面向想要自由的驾驭-css-动画的人详细解说附代码

大家好,这里是 UX(交互体验设计师)& 前端开发,并且还喜欢画画的 yuki!@yuneco。 在这篇文章里,为了能够更加轻松地去使用 Vue 和 css animation,基础的部分,将会跟大家一步步的详细解释。目标如下图↓所示,用 JavaScript 自由的控制动画。 源码送上 https://github.com/yuneco/css-anime-tutorial 目录那么先从最简单的 svg 标签开始。用 Vue 自由地配置、使其变形。然后利用 css 的 transition 来做动画,最后把动画抽象封装,运用到更加复杂的场景上。 制作 svg创建 Vue 项目显示 svg能够自由配置能够更自由更大角度的变化赋予动画能够连续进行动画抽象封装动画注意点这篇文章介绍的方法并不是使用动画时通用的方法。想要制作更复杂的动画,请使用 anime.js 或者 pixi.js。这篇文章并没有使用专门的动画库,而是自己封装的动画,目标是为了更加深入地理解 Vue、javascript、css 动画。虽然还有很多理由,但能点亮自己的【自己组建能够理解的动画】这方面的技能树,无疑也是很高兴的。文章稍稍有点长,如果你能看完的话,那我也很高兴。 制作 svg第一步,显示这篇教程要使用到的 svg,用 Illustrator 制作自己喜欢的角色去,依次从菜单上选择 [ファイル] -> [書き出し] -> [スクリーン用に書き出し],格式选择 svg,从右边齿轮一样的图标,显示设定。 设定看起来有点复杂的????,这里在 Vue 也没有那么麻烦的去使用 svg,所以这里的设定不需要太在意,右下角的 Responsive(レスポンシブ) 选择记得要取消掉。 设定好了之后,「設定を保存」->「アートボードを書き出し」导出 svg 文件,没有 Illustrator 的同学用其它的文件也 ok。怕麻烦的同学,我姑且在 github 上也放了一份... 用浏览器打开,大概就是这种感觉,名字叫 tama桑,现在刚决定的。为了方便理解,我特意加了 1 像素的边框。 创建 Vue 项目不管怎么说,不创建的 Vue 项目的话,就没法开始。运行,vue create 项目的名字 创建项目,就像下面一样,当然,你也可以根据自己的喜好来。 ...

July 5, 2019 · 7 min · jiezi

帧动画内存OOM不存在的-SurfaceView逐帧解析

Android 提供了AnimationDrawable用于实现帧动画。在动画开始之前,所有帧的图片都被解析并占用内存,一旦动画较复杂帧数较多,在低配置手机上容易发生 OOM。即使不发生 OOM,也会对内存造成不小的压力。下面代码展示了一个帧数为4的帧动画: 原生帧动画AnimationDrawable drawable = new AnimationDrawable();drawable.addFrame(getDrawable(R.drawable.frame1), frameDuration);drawable.addFrame(getDrawable(R.drawable.frame2), frameDuration);drawable.addFrame(getDrawable(R.drawable.frame3), frameDuration);drawable.addFrame(getDrawable(R.drawable.frame4), frameDuration);drawable.setOneShot(true);ImageView ivFrameAnim = ((ImageView) findViewById(R.id.frame_anim));ivFrameAnim.setImageDrawable(drawable);drawable.start();有没有什么办法让帧动画的数据逐帧加载,而不是一次性全部加载到内存?SurfaceView就提供了这种能力。 SurfaceView屏幕的显示机制和帧动画类似,也是一帧一帧的连环画,只不过刷新频率很高,感觉像连续的。为了显示一帧,需要经历计算和渲染两个过程,CPU 先计算出这一帧的图像数据并写入内存,然后调用 OpenGL 命令将内存中数据渲染成图像存放在 GPU Buffer 中,显示设备每隔一定时间从 Buffer 中获取图像并显示。 上述过程中的计算,对于View来说,就好比在主线程遍历 View树 以决定视图画多大(measure),画在哪(layout),画些啥(draw),计算结果存放在内存中,SurfaceFlinger 会调用 OpenGL 命令将内存中的数据渲染成图像存放在 GPU Buffer 中。每隔16.6ms,显示器从 Buffer 中取出帧并显示。所以自定义 View 可以通过重载onMeasure()、onLayout()、onDraw()来定义帧内容,但不能定义帧刷新频率。 SurfaceView可以突破这个限制。而且它可以将计算帧数据放到独立的线程中进行。下面是自定义SurfaceView的模版代码: public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback { public static final int DEFAULT_FRAME_DURATION_MILLISECOND = 50; //用于计算帧数据的线程 private HandlerThread handlerThread; private Handler handler; //帧刷新频率 private int frameDuration = DEFAULT_FRAME_DURATION_MILLISECOND; //用于绘制帧的画布 private Canvas canvas; private boolean isAlive; public BaseSurfaceView(Context context) { super(context); init(); } protected void init() { getHolder().addCallback(this); //设置透明背景,否则SurfaceView背景是黑的 setBackgroundTransparent(); } private void setBackgroundTransparent() { getHolder().setFormat(PixelFormat.TRANSLUCENT); setZOrderOnTop(true); } @Override public void surfaceCreated(SurfaceHolder holder) { isAlive = true; startDrawThread(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { stopDrawThread(); isAlive = false; } //停止帧绘制线程 private void stopDrawThread() { handlerThread.quit(); handler = null; } //启动帧绘制线程 private void startDrawThread() { handlerThread = new HandlerThread("SurfaceViewThread"); handlerThread.start(); handler = new Handler(handlerThread.getLooper()); handler.post(new DrawRunnable()); } private class DrawRunnable implements Runnable { @Override public void run() { if (!isAlive) { return; } try { //1.获取画布 canvas = getHolder().lockCanvas(); //2.绘制一帧 onFrameDraw(canvas); } catch (Exception e) { e.printStackTrace(); } finally { //3.将帧数据提交 getHolder().unlockCanvasAndPost(canvas); //4.一帧绘制结束 onFrameDrawFinish(); } //不停的将自己推送到绘制线程的消息队列以实现帧刷新 handler.postDelayed(this, frameDuration); } } protected abstract void onFrameDrawFinish(); protected abstract void onFrameDraw(Canvas canvas);}用HandlerThread作为独立帧绘制线程,好处是可以通过与其绑定的Handler方便地实现“每隔一段时间刷新”,而且在Surface被销毁的时候可以方便的调用HandlerThread.quit()来结束线程执行的逻辑。DrawRunnable.run()运用模版方法模式定义了绘制算法框架,其中帧绘制逻辑的具体实现被定义成两个抽象方法,推迟到子类中实现,因为绘制的东西是多样的,对于本文来说,绘制的就是一张张图片,所以新建BaseSurfaceView的子类FrameSurfaceView:逐帧解析 & 及时回收public class FrameSurfaceView extends BaseSurfaceView { public static final int INVALID_BITMAP_INDEX = Integer.MAX_VALUE; private List<Integer> bitmaps = new ArrayList<>(); //帧图片 private Bitmap frameBitmap; //帧索引 private int bitmapIndex = INVALID_BITMAP_INDEX; private Paint paint = new Paint(); private BitmapFactory.Options options = new BitmapFactory.Options(); //帧图片原始大小 private Rect srcRect; //帧图片目标大小 private Rect dstRect = new Rect(); private int defaultWidth; private int defaultHeight; public void setDuration(int duration) { int frameDuration = duration / bitmaps.size(); setFrameDuration(frameDuration); } public void setBitmaps(List<Integer> bitmaps) { if (bitmaps == null || bitmaps.size() == 0) { return; } this.bitmaps = bitmaps; //默认情况下,计算第一帧图片的原始大小 getBitmapDimension(bitmaps.get(0)); } private void getBitmapDimension(Integer integer) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(this.getResources(), integer, options); defaultWidth = options.outWidth; defaultHeight = options.outHeight; srcRect = new Rect(0, 0, defaultWidth, defaultHeight); requestLayout(); } public FrameSurfaceView(Context context) { super(context); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); dstRect.set(0, 0, getWidth(), getHeight()); } @Override protected void onFrameDrawFinish() { //在一帧绘制完后,直接回收它 recycleOneFrame(); } //回收帧 private void recycleOneFrame() { if (frameBitmap != null) { frameBitmap.recycle(); frameBitmap = null; } } @Override protected void onFrameDraw(Canvas canvas) { //绘制一帧前需要先清画布,否则所有帧都叠在一起同时显示 clearCanvas(canvas); if (!isStart()) { return; } if (!isFinish()) { drawOneFrame(canvas); } else { onFrameAnimationEnd(); } } //绘制一帧,是张Bitmap private void drawOneFrame(Canvas canvas) { frameBitmap = BitmapUtil.decodeOriginBitmap(getResources(), bitmaps.get(bitmapIndex), options); canvas.drawBitmap(frameBitmap, srcRect, dstRect, paint); bitmapIndex++; } private void onFrameAnimationEnd() { reset(); } private void reset() { bitmapIndex = INVALID_BITMAP_INDEX; } //帧动画是否结束 private boolean isFinish() { return bitmapIndex >= bitmaps.size(); } //帧动画是否开始 private boolean isStart() { return bitmapIndex != INVALID_BITMAP_INDEX; } //开始播放帧动画 public void start() { bitmapIndex = 0; } private void clearCanvas(Canvas canvas) { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPaint(paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); }}FrameSurfaceView继承自BaseSurfaceView,所以它复用了基类的绘制框架算法,并且定了自己每一帧的绘制内容:一张Bitmap。Bitmap资源 id 通过setBitmaps()传递进来, 绘制一帧解析一张 ,在每一帧绘制完毕后,调用Bitmap.recycle()释放图片 native 内存并去除 java 堆中图片像素数据的引用。这样当 GC 发生时,图片像素数据可以及时被回收。一切都是这么地能够自圆其说,我迫不及待地运行代码并打开AndroidStudio的Profiler标签页,切换到MEMORY,想用真实内存数据验证下性能。但残酷的事实狠狠地打了下脸。。。多次播放帧动画后,内存占用居然比原生AnimationDrawable还大,而且每播放一次,内存中都会多出 N 个Bitmap对象(N为帧动画总帧数)。唯一令人欣慰的是,手动触发 GC 后帧动画图片能够被回收。(AnimationDrawable中的图片数据不会被 GC) ...

May 10, 2019 · 4 min · jiezi

css动画-实现一个最简单的水波纹效果button

类似material-ui的button效果步骤1. 在页面写出一个button 并赋予简单的样式代码<body> <div> <button>这是一个按钮</button> </div></body>button { display: block; /* button 默认是inline-block 无法用margin给它居中 / margin: 50px auto; height: 60px; width: 150px; color: #FFF; font-size: 16px; background: #E95546; outline: none; border: 0; cursor: pointer; / 为了增加用户体验 / position: relative; / 为了保持和ripple的位置关系 / overflow: hidden; / 为了遮盖超出的ripple /}效果2. 添加水波纹的基础css样式代码.ripple { position: absolute; / 为了保持和button的位置关系 / border-radius: 50% 50%; / 水波纹圆形 / background: rgba(255, 255, 255, 0.4); / 水波纹颜色 / / 下面与动画效果相关 是0%时候的状态 / / 默认的 transform-origin 是 center 即中心点 / transform: scale(0); -webkit-transform: scale(0); opacity: 1; }3. 给水波纹加上动画的css代码.rippleEffect { / 执行时长0.6s、效果为渐变(linear)、名称为rippleDrop的动画 / -webkit-animation: rippleDrop .6s linear; animation: rippleDrop .6s linear;}@keyframes rippleDrop { / 下面是动画100%时候的状态 */ 100% { transform: scale(2); -webkit-transform: scale(2); opacity: 0; }}@-webkit-keyframes rippleDrop { 100% { transform: scale(2); -webkit-transform: scale(2); opacity: 0; }}4. 最后添加点击事件代码$(“button”).click(function (e) { $(".ripple").remove(); // 每次先把之前添加的水波纹div删除 let button_left = $(this).offset().left; // button距离页面左边的距离 let button_top = $(this).offset().top; // button距离页面上边的距离 let button_width = $(this).width(); // button的宽度 let button_height = $(this).height(); // button的高度 // 水波纹div为一个圆形,使得它的半径等于button的最长边,故在这里计算最长边是多少 let ripple_width = 0; ripple_width = button_width > button_height ? button_width : button_height; // e.pageX是click事件的鼠标触发点距离页面左边的距离 // e.pageY是click事件的鼠标触发点距离页面上边的距离 // 这里的算法是,算出鼠标点击点的坐标为 (e.pageX - button_left, e.pageY - button_top) // 但是由于transform-origin默认是center,所以这里再减去半径才是div应该的位置 let ripple_x = e.pageX - button_left - ripple_width / 2; let ripple_y = e.pageY - button_top - ripple_width / 2; // 往button里面塞水波纹div $(this).prepend("<div class=‘ripple’></div>"); // 给水波纹div应用样式和动画 $(".ripple") .css({ width: ripple_width + ‘px’, height: ripple_width + ‘px’, top: ripple_y + ‘px’, left: ripple_x + ‘px’ }) .addClass(“rippleEffect”);})Attention 别忘了引入jquery哦<script src=“https://cdn.bootcss.com/jquery/2.2.3/jquery.min.js"></script>效果END源码地址 ...

March 7, 2019 · 2 min · jiezi

css动画实现loading效果

css animation 动画实现loading状态HTML<div class=“root”></div> CSS.root { width: 25px; height: 25px; border-radius: 50px; border: 2px dashed #ddeeff; animation: loading 1s infinite linear;}@keyframes loading { to { transform: rotate(180deg) }}JavaScriptsetTimeout(() => { $(’.root’).css({ ‘animation-play-state’: ‘paused’ }) }, 5000)

January 19, 2019 · 1 min · jiezi

css3动画transition && animation

css 动画:transition(过渡)因为有些属性动画无意义,所以可动画属性集是一个有限集合其属性为如下几部分:transition-property:指定哪个或哪些 CSS 属性用于过渡transition-duration:指定过渡的时长。或者为所有属性指定一个值,或者指定多个值,为每个属性指定不同的时长transition-timing-function:指定一个函数(根据四个点确定一个bezier曲线),定义属性值怎么变化,值;也可以从 Easing Functions Cheat Sheet 选择缓动效果bezier 曲线定义可以具体看MDN上的timing functions cubic-bezier 又称三次贝塞尔,主要是为 animation 生成速度曲线的函数,规定是 cubic-bezier(<x1>, <y1>, <x2>, <y2>)。P0:默认值 (0, 0)P1:动态取值 (x1, y1)P2:动态取值 (x2, y2)P3:默认值 (1, 1)大概效果图–p3的坐标本应该为(1,1),这是css默认的(tips:偷不到图,自己又不想画)横坐标(abscissas)范围必须是[0, 1],纵坐标(ordinate)范围如果超出[0, 1],会有弹跳效果–由于兼容性的问题,这个效果还是别考虑了transition-delay: 指定延迟,即属性开始变化时与过渡开始发生时之间的时长在使用过程中简写:transition: <property> <duration> <timing-function> <delay>;/* 分开写,可以不一一对应,如4个property对应一个duration /.transition { position: absolute; top: 20px; left: 20px; width: 40px; height: 40px; border-radius: 50%; background-color: red; / transition-property: left color width height; transition-duration: 1.2s; transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1); transition-delay: 80ms; */ transition: all 1.2s cubic-bezier(0.23, 1, 0.32, 1) 80ms; &–move { left: 400px; background-color: cornflowerblue; width: 100px; height: 100px; transform: translateY(100px) }}检测过渡是否完成,这样就可以将css过渡和js动画结合起来el.addEventListener(“transitionend”, updateTransition, true);所以,所有property指定的属性,在值发生改变的的时候,都会遵循duration、timing-function、delay等定义的过度效果达到最后一帧的状态,并保持下来,至于transform,和width等一样,只是一个改变时可以触发transition过渡效果的可动画属性集合中的一个属性,transition,transform基本兼容到ie10。css 动画:animation(动画)属性描述animation-name动画名称animation-duration一个周期的时间(ms \s)animation-timing-function缓冲效果函数animation-delay动画执行前延迟时间(ms \s)animation-iteration-count动画执行的次数animation-direction动画是否反向播放animation-fill-mode动画执行之前和之后如何给动画的目标应用样式(停留在哪一帧)animation-play-state动画暂停/播放(用于js控制动画object.style.animationPlayState=“paused”,default: running)注:以上顺序是简写顺序@keyframes animationname {keyframes-selector {css-styles;}}值描述animationname动画名称keyframes-selector定义帧css-styles该帧的样式一个可控的动画<button @click=“animationMove”>stopAnimation</button><div class=“animation” ref=“animation”></div>animationMove (): void { let stateg = ‘paused’ if (this.$refs.animation.style.animationPlayState === ‘paused’) { state = ‘running’ } this.$refs.animation.style.animationPlayState = state}.animation { position: absolute; border-radius: 50%; top: 120px; animation: move 1.2s ease-in 80ms infinite alternate;}@keyframes move { 0% { left: 20px; background-color: red; width: 40px; height: 40px; transform: translateY(0) } 100% { left: 400px; background-color: rgb(169, 185, 214); width: 100px; height: 100px; transform: translateY(100px) }}动画和过渡的相同之处应该就是缓冲函数不可变,不同之处就是动画可以定义多个关键帧,过渡只能定义两个关键帧(起始帧和结束帧)动画修改一个元素的 width 和 height 会改变它的形状,而且可能引起页面上其它元素的移动和形状改变,这个过程称为布局。基于 CSS 的动画和原生支持的 Web 动画通常在称为合成器线程的线程上处理,transforms 和 opacity 都可以在合成器线程中处理;它与浏览器的主线程不同,在该主线程中执行样式,布局,绘制和 JavaScript。这意味着如果浏览器在主线程上运行一些耗时的任务,这些动画可以继续运行而不会中断;如果任何动画出发了绘制,布局,或者两者,那么主线程会来完成该工作。这个对基于 CSS 还是 JavaScript 实现的动画都一样,布局或者绘制的开销巨大,让与之关联的 CSS 或 JavaScript 执行工作、渲染都变得毫无意义;避免使用触发布局或绘制的属性动画。对于大多数现代浏览器,这意味着将动画(修改的属性)限制为 opacity 和 transform;参考:How JavaScript works: Under the hood of CSS and JS animations + how to optimize their performanceMDN:transitionMDN:animation ...

December 29, 2018 · 1 min · jiezi

10分钟入门 CSS3 Animation

简介Animation可以让你不用依赖javascript或jquery,用纯CSS在网页中轻松实现各种动画效果。兼容性animation在绝大部分主流浏览器都得到了很好的支持!还在兼容IE9的同学要谨慎使用。CSS 坐标系在了解animtion之前,我们有必要先了解css的坐标系,因为很多的animation效果都和元素的坐标密切相关。在css3中网页不再是一个二维平面,而是一个三维空间,水平方向、竖直方向和垂直屏幕方向分别对应三维坐标系的x,y,z轴,如下图所示。箭头方向为正向,反之为负向(注意y轴方向与常规笛卡尔坐标系相反)。Animations1. Transformstransform中文译为“转换”,但我更倾向于称呼它“变形”(大名鼎鼎的变形金刚叫transformer)。我们可以使用transform function使html元素产生各种各样的变形,比如平移、缩放、旋转、扭曲等,而且不会影响正常的文档流(document flow)。(1) TranslateTranslate一般译为“翻译”,但在css里面一般用作“平移”,因为translate用于改变html元素的在3d坐标系位置。translate支持在坐标系内任意方向移动(通过任意组合x、y、z方向的向量),单位可以是长度单位和百分比(百分比是相对于被平移的元素自身尺寸,x轴是相对于width,y轴是相对于height,而在z轴方向由于元素是没有‘厚度’的,所以对于z方向不能用百分比表示),例如:transform: translateX(100px) translateY(50%) translateZ(-100px);// 或者简写transform: translate3d(100px, 50%, 2em);注意:translate是xy平面内的2维平移,translate3d是xyz空间内的三维平移;translate也可以单独书写,如 translate: 50% 105px 5rem;,但是该特性尚在实验阶段,很多浏览器不支持,所以现阶段还是配合transform使用。详情参考 MDN translate。(2) ScaleScale意为“缩放”,顾名思义,是用于改变元素的大小。例如:transform: scaleX(2) scaleY(0.5) scaleZ(1);// 或者简写transform: scale3d(2, 0.5, 1);scale方法接收任意数字(正负整数、小数、0)作为参数,该参数为缩放系数,系数>1 效果为放大,0<系数<1 效果为缩小,系数=0 元素尺寸变为无限小而不可见,系数<0 效果为 >0 时的镜像(具体效果可自己实验)。与translate类似,scale也有2维 scale() 和三维 scale3d()之分,也可以单独书写,此处不赘述。(3) RotateRotate意为“旋转”,支持将元素以x、y、z为轴旋转,旋转正方向为面朝坐标轴正向逆时针方向,可参考上面坐标系示意图。rotate方法接收一个角度作为参数,角度>0 正向旋转,角度<0 负向旋转,例如:// 默认绕z轴旋转transform: rotate(90deg);transform: rotateX(30deg) rotateY(60deg) rotateZ(-90deg);与translate和scale不同,rotate不能简写为transform: rotate3d(30deg, 60deg, 90deg)的形式,rotate3d的用法为:前三个参数为数字,代表x、y、z方向的向量,相加得到向量v,第四个参数为角度,表示以向量v为轴逆时针旋转的角度,语法如下:transform: rotate3d(1, 2, 3, 90deg);与translate和scale类似,rotate也可以作为单独的css属性,但还在实验阶段。出于篇幅考虑,我只列出三种最常用的tranform function,剩下的transform function请参考 MDN transform function。(4) 组合我们可以将不同的transform方法组合起来使用,如:transform: translateY(200px) rotateZ(90deg) scale(3);组合方法的执行顺序是从右往左,即先执行scale,然后rotate,最后translate,产生的效果是逐次累加的。方法书写的顺序对最后效果有很大的影响,看下面例子,沿y轴平移和放大,顺序不同,产生的结果有明显差别:如果先translate再scale,平移的距离也将被等比例缩放,而先scale再translate则不会。所以在使用transform需按照 translate -> rotate -> scale 的顺序书写,让scale先执行,以免放大translate的效果,而rotate先translate执行以防止带着平移的距离一起转动。我觉得这是transform目前不方便的地方,因为方法之间相互干扰并不容易理解,书写顺序也不容易记住。在未来有望通过使用独立的css transform属性解决这一问题,因为独立的transform属性对书写顺序没有依赖,方法之间彼此不会干扰。TransitionTransition翻译为“过渡”,强调的是过程。在css中指在一段时间内,元素从一个状态(对应一个css属性)过渡到另一个状态的动态过程。我们可以决定以何种方式过渡过渡和花费多少时间。例如,我们把鼠标悬浮到云上面的时候使其变大一些可以这么写:.cloud{ width: 240px; transition: 1s;}.cloud:hover{ width: 320px;}效果:transition可以和transform结合使用,比如我们可以让云变大的同时转一圈:.cloud:hover{ width: 320px; transform: rotate(360deg);}效果:我们可以给不同的效果设置不同的过渡时间:.cloud{ width: 240px; transition: width 1s, transform 0.5s;}我们也可以给效果设置延时时间,比如我们等宽度增大之后再旋转:.cloud{ width: 240px; transition: width 1s, transform 0.5s 1s;}效果:我们还可以给每个效果设置不同的timing function,用于控制加速效果。比如我们可以让旋转的速度逐渐加快:.cloud{ width: 240px; transition: transform 2s ease-in;}.cloud:hover{ transform: rotate(1080deg);}效果:更多的timing function请后面会进一步讨论,也可以参考 MDN transition-timing-functionsKeyframes(1) 基本用法Keyframe中文译为“关键帧”,是animation中很强大的功能,通俗说就是我们可以通过定义一段动画中的关键点、关键状态来创建动画。Keyframes相比transition对动画过程和细节有更强的控制。我们先看一个例子(部分代码省略)html:<div class=“sky”></div><div class=“grass”></div><div class=“road”> <div class=“lines”></div> <img src=“http://lc-jOYHMCEn.cn-n1.lcfile.com/a3f630c957a4b32d0221.png" class=“mario animated”></div>css:.mario{ position: absolute; left: 0px; width: 100px;}.animated{ animation-name: drive; animation-duration: 1s; animation-timing-function: linear;}@keyframes drive { from{ transform: translateX(0) } to{ transform: translateX(700px) }}效果:其中 drive 是该keyframes的名称,from, to 是keyframes播放过程的时间起点和终点,时间点也可以用百分比表示,如50%,from, to 等价于 0%, 100%。每个时间点对应一个css状态,代表一个关键帧(keyframe)。keyframes定义完成后使用方法如下:animation也有简写形式,如:animation: slidein 3s ease-in 1s infinite reverse both running;但这种对书写顺序有一定要求(delay要写在duration后面,其他参数无顺序要求,css会通过传入的关键词识别)。(2) Animation Delay通过animation-delay,我们可以给动画延迟执行:animation-delay: 2s;(3) Animation Fill Modeforwards在上面的例子中可以看到马里奥运动到右边之后又回到了起点,如果我们想让他运动完成后就停留在右边呢?很简单,我们设置annimation fill mode就可以了:animation-fill-mode: forwardsforwards 表示动画完成后,元素将保持最后一帧的状态。backwards与之相对的还有 backwards,backwards表示并不是动画完成后元素变回第一帧的状态,而是表示当设置了animation-delay时,在动画开始前的等待过程中,立刻给元素应用第一帧的状态。我们将上面的例子稍作修改看一下效果:.animated{ animation-name: drive; animation-duration: 1s; animation-fill-mode: backwords; animation-delay: 1s; animation-timing-function: linear;}@keyframes drive { from{ transform: translateX(350px) } to{ transform: translateX(700px) scale(2) }}效果:可以看到,动画开始之前小人立马移动到350px处,1s之后才开始动画。both显而易见,both会同时应用forwards和backwards两种规则,即在delay时先应用第一帧的状态,结束时保持最后一帧的状态。(3) Animation Repeat我们可以通过 animation-iteration-count 设置动画循环播放的次数,比如:animation-iteration-count: 3;// 无限循环animation-iteration-count:infinite;就像这样:(4) Animation Directionnormal正常方向,也是默认方向,即先from,再to。reverse与正常方向相反,即先to,再from。例如:.animated{ … animation-direction: reverse;}@keyframes drive { from{ transform: translateX(-100px) rotateY(180deg) } to{ transform: translateX(862px) rotateY(180deg)}}效果:alternatealternate意为“交替”,即normal和reverse交替之行,先normal再reverse。reverse alternate反向交替,先reverse再normal。(4) Animation Timing function和transition一样,keyframes也可以设置timing function,常用的timing function归纳如下:ease:默认方法,初速度较慢,然后加速再减速ease-in:初速度最慢,然后一直加速ease-out:初速度最快,然后一直减速ease-in-out:初速度较慢,然后加速再减速,与ease的区别在于加速减速过程是对称的linear:恒速运动直观表现如下(codepen):除了上面现成的方法,我们可以通过贝塞尔曲线自定义速度曲线。我们可以在 http://cubic-bezier.com 可视化的创建我们自己的贝塞尔曲线。比如创建一个刚开始极慢,突然变得极快的曲线:css:animation-timing-function: cubic-bezier(1,.03,1,-0.03);效果:是不是挺神奇!(5) Chain Animation我们可以将多个animation串联使用,比如我们想让小人在行驶的过程中跳跃,可以这么写:css:.mario { … animation: drive 3s both infinite linear, jump 0.5s 1.2s ease-in-out infinite;}@keyframes jump { 0% { top: -40px; } 50% { top: -120px; } 100% { top: -40px; }}效果:实践本文目的在于普及css3 animation的基础,并未完全覆盖animation的知识,未涉及和讲解的知识请大家见谅 。 掌握上述知识后,我们就已经可以用animation做出丰富的动画效果了,下面列出一些codepen上的小例子:full mario demoanimated popupfly items to shopping cartflipping cards ...

December 25, 2018 · 2 min · jiezi

前端每日实战:127# 视频演示如何用纯 CSS 创作一个圆环旋转错觉动画(实际上没有任何元素在做旋转运动)

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/oPWJNj/可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cbvPWHM源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 10 个 <div> 子元素,每个 <div> 子元素内还有一个 <span> 子元素:<figure class=“container”> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div> <div><span></span></div></figure>定义容器尺寸:.container { width: 17em; height: 17em; font-size: 16px;}定义子元素的尺寸,和容器相同:.container { position: relative;}.container div { position: absolute; width: inherit; height: inherit;}在子元素的正中画一个黄色的小方块:.container div { display: flex; align-items: center; justify-content: center;}.container span { position: absolute; width: 1em; height: 1em; background-color: yellow;}增加让小方块左右移动的动画效果,动画时长还会在后面用到,所以定义成变量:.container span { –duration: 2s; animation: move var(–duration) infinite;}@keyframes move { 0%, 100% { left: calc(10% - 0.5em); } 50% { left: calc(90% - 0.5em); }}用贝赛尔曲线调整动画的时间函数,使小方块看起来就像在左右两侧跳来跳去:.container span { animation: move var(–duration) cubic-bezier(0.6, -0.3, 0.7, 0) infinite;}增加小方块变形的动画,使它看起来有下蹲起跳的拟人效果:.container span { animation: move var(–duration) cubic-bezier(0.6, -0.3, 0.7, 0) infinite, morph var(–duration) ease-in-out infinite;}@keyframes morph { 0%, 50%, 100% { transform: scale(0.75, 1); } 25%, 75% { transform: scale(1.5, 0.5); }}至此,完成了 1 个方块的动画。接下来设置多个方块的动画效果。为子元素定义 CSS 下标变量:.container div:nth-child(1) { –n: 1; }.container div:nth-child(2) { –n: 2; }.container div:nth-child(3) { –n: 3; }.container div:nth-child(4) { –n: 4; }.container div:nth-child(5) { –n: 5; }.container div:nth-child(6) { –n: 6; }.container div:nth-child(7) { –n: 7; }.container div:nth-child(8) { –n: 8; }.container div:nth-child(9) { –n: 9; }旋转子元素,使小方块分布均匀地在容器的四周,围合成一个圆形:.container div { transform: rotate(calc(var(–n) * 40deg));}设置动画延时,现在看起来就像是一群小方块贴着一个圆的内边线在旋转了(但实际上没有任何元素在做旋转运动,大脑感觉到的旋转是一种错觉):.container span { animation-delay: calc(var(–duration) / 9 * var(–n) * -1);}最后,为小方块上色:.container span { background-color: hsl(calc(var(–n) * 80deg), 100%, 70%);}大功告成! ...

September 5, 2018 · 1 min · jiezi

前端每日实战:125# 视频演示如何用纯 CSS 创作一个失落的人独自行走的动画

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/MqpOdR/可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/czZnbsr源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 3 个元素,分别代表头、身体和脚:<div class=“man”> <span class=“head”></span> <span class=“body”></span> <span class=“feet”></span></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background: radial-gradient(lightgray 20%, whitesmoke);}定义容器尺寸:.man { width: 12em; height: 33em; font-size: 10px; position: relative;}定义主色:.man { color: white;}画出头部:.head { position: absolute; width: 7em; height: 7em; background-color: currentColor; border-radius: 50%; right: 0;}画出身体:.body { position: absolute; width: 6.2em; height: 14.4em; background-color: currentColor; top: 7em; border-radius: 100% 20% 0 0;}画出脚,现在只能看到一只脚,是因为两只脚重叠在一起,一会儿动起来时就能看到两只脚了:.feet::before,.feet::after { content: ‘’; position: absolute; width: 4em; height: 1.4em; background-color: white; bottom: 0; left: -1.6em; border-radius: 1em 80% 0.4em 0.4em;}用伪元素画出阴影:.man::before { content: ‘’; position: absolute; width: 12em; height: 0.8em; background-color: rgba(0, 0, 0, 0.1); bottom: -0.2em; left: -3em; border-radius: 50%;}接下来增加动画效果。增加行走的动画效果,并使两只脚的动画时间交错:.feet::before,.feet::after { animation: feet-animation 2s ease-in-out infinite;}.feet::after { animation-delay: 1s;}@keyframes feet-animation { 20% { transform: translateX(3.4em) translateY(-1.6em) rotate(4deg); } 30% { transform: translateX(4.6em) translateY(-1em) rotate(0deg); } 40% { transform: translateX(5.6em) translateY(-0.6em) rotate(4deg); } 44% { transform: translateX(5.6em) translateY(0) rotate(0deg); }}增加头和身体起伏的动画效果:.head,.body { animation: body-animation 4s ease-in-out infinite;}@keyframes body-animation { 0%, 100% { transform: translateY(0) skewX(-2deg); } 25%, 75% { transform: translateY(0.5em) skewX(0deg); } 50% { transform: translateY(0) skewX(0deg); }}增加阴影面积随身体运动而变化的动画效果:.man::before { animation: shadow-animate 4s ease-in-out infinite;}@keyframes shadow-animate { 0%, 50%, 100% { transform: scale(1); } 25%, 75% { transform: scale(1.15); }}大功告成! ...

September 3, 2018 · 1 min · jiezi

前端每日实战:122# 视频演示如何用纯 CSS 创作一个苹果系统的相册图标

效果预览按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。https://codepen.io/comehope/pen/zJKwbO可交互视频此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。请用 chrome, safari, edge 打开观看。https://scrimba.com/p/pEgDAM/cDBZNUW源代码下载每日前端实战系列的全部源代码请从 github 下载:https://github.com/comehope/front-end-daily-challenges代码解读定义 dom,容器中包含 8 个元素,每个元素代表一个矩形色块:<div class=“icon”> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span> <span></span></div>居中显示:body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #ccc;}定义容器尺寸:.icon { width: 10em; height: 10em; font-size: 30px; background-color: #eee; border-radius: 20%;}绘制出矩形的轮廓(边框为辅助线,最终会被删除),并放置在容器的中上方:.icon { position: relative; display: flex; justify-content: center; box-sizing: border-box; padding: 1em;}.icon span { position: absolute; width: 22.5%; height: 37.5%; border: 1px dashed black; border-radius: 50% / 30%;}为矩形设置下标变量 –n:.icon span:nth-child(1) { –n: 1;}.icon span:nth-child(2) { –n: 2;}.icon span:nth-child(3) { –n: 3;}.icon span:nth-child(4) { –n: 4;}.icon span:nth-child(5) { –n: 5;}.icon span:nth-child(6) { –n: 6;}.icon span:nth-child(7) { –n: 7;}.icon span:nth-child(8) { –n: 8;}让 8 个矩形依次旋转固定的角度,围合成一个圆形:.icon span { transform-origin: center 105%; transform: rotate(calc((var(–n) - 1) * 45deg));}为矩形设置颜色变量 –c:.icon span:nth-child(1) { –c: rgba(243, 156, 18, 0.7);}.icon span:nth-child(2) { –c: rgba(241, 196, 15, 0.7);}.icon span:nth-child(3) { –c: rgba(46, 204, 113, 0.7);}.icon span:nth-child(4) { –c: rgba(27, 188, 155, 0.7);}.icon span:nth-child(5) { –c: rgba(65, 131, 215, 0.7);}.icon span:nth-child(6) { –c: rgba(102, 51, 153, 0.7);}.icon span:nth-child(7) { –c: rgba(155, 89, 182, 0.7);}.icon span:nth-child(8) { –c: rgba(242, 38, 19, 0.7);}为 8 个矩形上色,并删除掉起辅助线作用的边框:.icon span { /* border: 1px dashed black; */ background-color: var(–c);}设置混色模式,使重叠颜色能叠加在一起:.icon span { mix-blend-mode: multiply;}增加鼠标悬停效果,当悬停时运行矩形色块展开的动画:.icon:hover span { animation: rotating 2s ease-in-out forwards;}@keyframes rotating { from { transform: rotate(0deg); } to { transform: rotate(calc((var(–n) - 1) * 45deg)); }}注意,在动画过程中第 1 个矩形并没有转动,因为它是从 0 度转到 0 度,为了让它转动,要把它的结束角度设置为 360 度,通过修改它的下标变量来实现:.icon span:nth-child(1) { –n: 9;}大功告成! ...

August 30, 2018 · 2 min · jiezi