Android Animation Made Easy
原文链接 Android Animation Made Easy
动画在任何一个GUI系统中都是一个非常重要的设计元素,它可以让交互变得优雅,让界面变得炫酷,让操作变得更加的舒畅,让状态过渡变得更加的顺滑,对视觉效果有极大的提升,时而提升用户体验,特别是对于移动应用来说,更是如此。就好比水果平台,最为吸引人的地方就在于其炫酷流畅的动画效果。早期的Android,在动画这一块确实差,不过,近些年,随着谷歌不断的加大力度在提升,现在来说安卓在动画这一块已经跟水果差不多了。今天就来聊一聊关于动画的话题。

动画的种类
一般来说动画分为二个种类:
逐帧动画(Frame Animation)也叫做Drawable Animation
也就是电影胶片式的,一张张不同的画连在一起播放,比较简单,只需要准备足够帧数(数量)的图片,就可以了。缺点也比较明显,需要比较多的资源(图片,存储空间,内存空间以及CPU资源)。并且灵活性非常的差,不能让普通的一段文字或者一个按扭进行动画。
针对某些特别简单的动画可以用此方式来实现,比如像简单的进度条,或者滑动引导提示等,具体的方式就是:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"android:oneshot="true"> <item android:drawable="@drawable/rocket_thrust1" android:duration="200" /><item android:drawable="@drawable/rocket_thrust2" android:duration="200" /><item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>
补间动画(Tween Animation)
补间动画比帧动画就要高级一些,因为充分利用了计算机的特性,只需要告诉起始状态和结束状态,然后让计算机去计算中间的状态,再不用把每一帧都告诉计算机了。在安卓中就是View Animation,以及后来的强大的Property Animation。
动画的基本原理
动画,其实就是一组快速播放的幻灯片,每一张(每一帧)的状态略有不同,快速连起来播放,由于人的眼睛有视觉残留效应,这就形成了动画。对于计算机程序来说,一般的动画就是给定对象的初始和终末状态,在一定时间内,不断的计算中间过程,并以视觉的方式展示出来,这就是动画。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ujh0qqTO-1691408239181)(https://developer.android.com/images/animation/animation-linear.png)]
动画的关键要素
一个动画必须要有以下关键的要素:
- 时长(Duration),也就 说播放动画的总时长,系统默认是300ms
- 时间插值器(Interpolation),就是动画的关键参数随时间要如何变化
- 重播(Repeat),包括重播的次数以及方式,次数好理解,方式的意思是,可以顺序的一遍一遍的播,也是可以反着播
- 延迟(Delay),动画启动的延时,通常用在动画组合里面。
View Animation
这是从安卓一开始就支持的动画方式,仅能对View对象生效,使用起来也比较方便和简单,通过组合和自定义插值器,足以实现常用的视觉变幻(如渐变,旋转,缩放和位移)。
主要有四种位移(translation),透明度(alpha),旋转(rotation)和缩放(scaling)。还可以以集合的方式来把几个动画合在一起播放。可以设置动画的时长(duration),速率(interpolator),重复和事件的监听。
一些使用建议:
-
所有这些东西都是放在android.view.animation包下面的,所以这些东西只能用于View对象。其实绝大多数时候,这也不是问题,除了View,还有啥要做动画呢。
-
TranslateAnimation只能是直线运动,如果要曲线,就得自定义,可以参考这个。
-
scale可以实现水平或者垂直翻转。
-
动画的触发是当View需要invalidate的时候就会触发setAnimation指定的动画。所以,如下代码会正常触发:
TextView title; // 原来是GONE的 title.setVisibility(View.VISIBLE); title.setAnimation(new AlphaAnimation(0.3f, 1f);不一定非要startAnimation
-
要注意动画前后View的状态。这个比较难受。因为动画过程仅是放一遍电影(动画过程中仅是在View的绘制的时候对Canvas做变幻),对View本身并没有影响,通常的做法是给View Animation加上Listener,在onAnimationEnd的时候去设置目标状态。
总的来说,View animation简单易用,大部分场景是可以满足需求的,早期版本确实有一些缺陷,内部状态在动画过程中会有问题,但是最近新的Android版本上面,已没有大问题,所以当能满足需求时,使用也没有问题。
属性动画(Property Animation)
就像名字暗示那样,从3.0开始一套新的动画API出现了,可以描述为在一段时间内以一定的方式来改变某一个属性,是这样的方式来做动画。所以,它也可以做动画以外的事情。这套API的核心思想是在一段时间内,让某些属性随着时间改变(有点像中学的物理题)。
属性动画就是根据时间来改变某一对象(不一定非要是View)的某一个属性,至于某一时刻属性变化的值所产生的后果,由使用者自定义,因此你可以把它应用于任何对象。
它也与View一样,可以组合,可以设置事件监听。
与View动画最大的区别在于,View动画仅是按要求放一遍电影,不会对View的实际属性产生影响,因此,动画过程中以及完成后View仍是在原来的位置,属性也不会变化。而属性动画则不是,它会直接改变View的属性,所以有些时候这个优势会很方便,比如实现收起与展开的动画时Property动画会明显的优势:
比如,对于一个可以收起和弹出的动画,就可以这样来实现:
收起动画:
private void animateCollapse() {AnimatorSet set = new AnimatorSet();ObjectAnimator translate = ObjectAnimator.ofFloat(mStatusPanel, "translationY", 0f, mTranslationY);ObjectAnimator alpha = ObjectAnimator.ofFloat(mStatusPanel, "alpha", 1f, 0.75f);set.setDuration(250);set.setInterpolator(new AccelerateDecelerateInterpolator());set.playTogether(translate, alpha);set.start();}
弹出动画:
private void animateExpansion() {AnimatorSet set = new AnimatorSet();ObjectAnimator translate = ObjectAnimator.ofFloat(mStatusPanel, "translationY", mTranslationY, 0);ObjectAnimator alpha = ObjectAnimator.ofFloat(mStatusPanel, "alpha", 0.75f, 1f);set.setDuration(250);set.setInterpolator(new AccelerateDecelerateInterpolator());set.playTogether(translate, alpha);set.start();}
如果要使用View animation,也许也可以实现同样的效果,但估计会很难,因为要注意设置View的属性。比如说收起时并不是全hide,而是半折叠状态,就需要在AnimationListener#onAnimationEnd时去设置特殊的位置状态.
使用时候的建议:
-
属性动画是post layout的,所以所有属性的初始状态就是你在布局中指定的值,动画是以此为基础开始的。
-
比较难使用的是translationX和translationY属性,它们的定义是相对于left和top的值。或者理解为相对于layout之后的在父布局中的位置的左边和右边。比如:
ObjectAnimator.ofFloat(mBar, "translationY", 0, height);这个就是进入的动画,一个View从其上头滑入。反过来:
ObjectAnimator.ofFloat(mBar, "translationY", height, 0);就是滑出。
ValueAnimator
这是属性动画的核心类,其实它很好的诠释了什么是动画,它就是把某个值在duration内,按照插值器指定的方式从一个值变化到另一个值。看到这个类,就可以感知到动画跟View其实一点关系都没有,动画就是一个随时间变化 的数值而已。
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
这意思就是让一个浮点数变量,在1秒内,从0,变化 到100。至于这个有什么具体的效果,要看你如何应用这个随时间变化 的浮点数变量,比如用于控制进度,一般情况下都会将变化的数值用于改变View的视觉变幻形态,但并不局限于此,这里只是为了说明这个动画数值可以用于任何地方:
animation.addUpdateListener(anim -> {float t = (float) anim.getAnimatedValue();mStatusPanel.setText(String.format("Temperature: %04.1f", t));});
ObjectAnimator
它是ValueAnimator的一个子类,增强了点功能,它的作用是针对 给定的对象,对其指定的某个属性做动画插值,动画计算与前面提到的ValueAnimator是一样的,只不过说它可以对某个对象的指定的属性做计算,并改变这个属性:
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();
这意思就是说,把动画计算出来的数值应用于一个textView的translationX属性上面。它与下面的代码,用ValueAnimator来实现,是完全等效的:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator updatedAnimation) {float animatedValue = (float)updatedAnimation.getAnimatedValue();textView.setTranslationX(animatedValue);}
});
由此可见ObjectAnimator就是多做了一层封装,方便来操作而已。需要注意的是,对象的属性必须要有setter和getter,因为这里会用传进来的属性名字用反射去调用,所以必须要有属性对应的settter和getter方法。
ViewPropertyAnimator
因为大多数情况下是对View做动画,所以又封装出了一个专门用于View的属性动画工具,也即ViewPropertyAnimator,可以非常方便进行属性动画。用一个实例就会相当明了。
比如说想对某个View进行位置,用ObjectAnimator,就需要这么写:
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
但如果用ViewPropertyAnimator就会非常简洁:
myView.animate().x(50f).y(100f);
AnimatorSet
用于创建组合,前面的例子已经可以看出来它怎么使用的了。当需要同时实现多个变幻时,就可以把多个Animator用AnimatorSet来组合起来。这个类非常的灵活,可以设置不同的时长,延迟和重复。
插值器
插值器(Interpolators)用以调节数值与时间变化 的关系,因为动画是有时长的,是在duration内,从某个数值变化 到另一数值,而具体随时间怎么变,则由插值器决定。默认是线性的,比如250ms,0f到100,那么就是匀速运动。也可以加速的,减速的,先加速后减速,先减速后加速。
android.view.animation内定义了大量的插值器可供使用。
在XML中来声明动画
与布局类似,动画也是支持在XML中来声明的,这样可以减少代码量,加强复用。方式与方法与写代码差不多,只不过是放在了XML里面,如:
<set android:ordering="sequentially"><set><objectAnimatorandroid:propertyName="x"android:duration="500"android:valueTo="400"android:valueType="intType"/><objectAnimatorandroid:propertyName="y"android:duration="500"android:valueTo="300"android:valueType="intType"/></set><objectAnimatorandroid:propertyName="alpha"android:duration="500"android:valueTo="1f"/>
</set>
这就声明了一个AnimatorSet,是一个位移和渐变动画,使用时用AnimatorInflater 来加载load一下就可以了:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,R.animator.property_animator);
set.setTarget(myObject);
set.start();
支持的根节点有三个,AnimatorSet,ObjectAnimator和ValueAnimator:
- ValueAnimator - <animator>
- ObjectAnimator - <objectAnimator>
- AnimatorSet - <set>
对于XML中使用ValueAnimator也是一样的,定义好,然后加载出来就可以用了,其实跟前面用代码写是一样的:
<animator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:valueType="floatType"android:valueFrom="0f"android:valueTo="-100f" />
ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator updatedAnimation) {float animatedValue = (float)updatedAnimation.getAnimatedValue();textView.setTranslationX(animatedValue);}
});xmlAnimator.start();
注意:有一点需要注意的是,因为View Animation也是支持用XML方式来定义的,且是放在了res/anim下面。所以如果使用Property Animation 时要放在res/animator下面,这个一定要注意。
View状态变化动画
从安卓一开始,对于一些View的状态变化就可以设置不同的Drawable,以给用户视觉上的交互 反馈,最常见的比如按扭,常规状态,Focused状态和按压状态,以及Disabled的状态(不可点击)可以设置不同的Drawable(如icon或者颜色等)以告诉用户。这个是叫做StateListDrawable。
现如今,也可以针对 View的不同状态设置不同的动画了,通过StateListAnimator来实现,它的语法与前面提到的StateListDrawable类似,亦是通过一个selector,只不过其中的每个item都是animator,而非drawable,比如:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- the pressed state; increase x and y size to 150% --><item android:state_pressed="true"><set><objectAnimator android:propertyName="scaleX"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1.5"android:valueType="floatType"/><objectAnimator android:propertyName="scaleY"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1.5"android:valueType="floatType"/></set></item><!-- the default, non-pressed state; set x and y size to 100% --><item android:state_pressed="false"><set><objectAnimator android:propertyName="scaleX"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1"android:valueType="floatType"/><objectAnimator android:propertyName="scaleY"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1"android:valueType="floatType"/></set></item>
</selector>
这意思就是当点击的时候进行缩放动画,把其保存在res/xml/animate_scale.xml,这里需要注意,StateListDrawable是可以直接保存在res/drawable/下面的,但动画毕竟不是drawable,是不可以放在res/drawable下面。
通过android:stateListAnimator添加给指定的View,如:
<Button android:stateListAnimator="@xml/animate_scale"... />
如果不在XML中设置,用代码也可以,先用AnimatorInflater,把它加载出来,然后调用View#setStateListAnimator即可。
设计与实现要符合标准
一个不争的事实是,在安卓的早期版本的时候对动画支持并不友好,因此当时很多GUI的设计都是采用水果平台的规范,导致大量的头部app,GUI交互,特别是动画这一块都是尽可能 的去模仿水果平台。
但时代不一样了,现在在谷歌加大了对安桌的支持力度后,特别是当Material Design出来了以后,从Android 5.0 Lollipop开始,伟大的Google就发布了专门针对UED的设计语言Material Design它不再单单是设计规范了,而是一个非常详细的设计语言,具体到Icon怎么画,动画怎么做。那么,安桌的GUI交互设计与实现,就要符合Material Design的规范了,这样不但体验更符合安桌的风格,实现起来也更加的顺手,因为大量的标准库,AndroidX的库和风格主题动画等等都是以Material Design为标准的,开发人猿在实现的时候有更多的资源可以复用,不用再重复的去造轮子。
Anyway,官方的东西我们还是要学习的并尽可能的遵守的,特别是关于Material Design和Animation。
参考资料
- Animations and Transitions
- https://github.com/lgvalle/Material-Animations
- Implementing Material Design in Your Android app
- 如何学习 Android Animation
原创不易,打赏,点赞,在看,收藏,分享 总要有一个吧
相关文章:
Android Animation Made Easy
原文链接 Android Animation Made Easy 动画在任何一个GUI系统中都是一个非常重要的设计元素,它可以让交互变得优雅,让界面变得炫酷,让操作变得更加的舒畅,让状态过渡变得更加的顺滑,对视觉效果有极大的提升ÿ…...
56从零开始学Java之与字符串相关的正则表达式
作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦 千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 在上一篇文章中,壹哥给大家介绍了String字符串及其各种常用API方法,接下来壹哥…...
STM32 定时器自动重装载寄存器ARR带来的影响,ARPE0和1区别
ARR是啥 自动重载寄存器是预装载的。对自动重载寄存器执行写入或读取操作时会访问预装载寄存器。预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件 (UEV) 时传送到影子寄存器,这取决于 TIMx_CR1 寄存器中的自动重载预装载使能位 …...
vue 把<style scoped lang=“less“> 单独写成less文件再导入使用
1 npm npm install less-loader --save-dev2 创建一个单独的 Less 文件,例如 app.less <style scoped lang"less"> import url(./app.less); </style>3 在 app.less 文件中,编写 Less 样式代码 .container {width: 500px;margi…...
C++ 字符串
C 字符串 一、字符串两种写法 c语言的写法,可以延用 const char* str1 "huang"; char str2[] "Hello, World!";c写法 std::string str "Hello, World!";二、字符串计算长度 c语言的计算字符串长度,需要导入库 #inc…...
springboot 报错处理(长期更新 2023.8.10)
目录 一、HTTP 相关1.1、 数据传输方面1.1.1、 HttpMessageNotWritableException1.1.1.1、 springboot + stomp 场景一、HTTP 相关 1.1、 数据传输方面 1.1.1、 HttpMessageNotWritableException 1.1.1.1、 springboot + stomp 场景 报错内容: 使用 spring boot 和 stomp 服…...
Maven出现报错 ; Unable to import maven project: See logs for details错误的多种解决方法
问题现象; IDEA版本: Maven 版本 : 3.3.9 0.检查 maven 的设置 :F:\softeware\maven\apache-maven-3.9.3\conf 检查setting.xml 配置 本地仓库<localRepository>F:\softeware\maven\local\repository</localRepository>镜像…...
33_windows环境debug Nginx 源码-安装WSL
文章目录 前言安装 WSL先决条件启用 windows 更新功能真正安装 WSL133_windows环境debug Nginx 源码-安装WSL前言 虽然很想在纯 windows 环境,基于windows 的生态完成debug,但现实情况是 由于Nginx 源码编写的很多内容都和 linux 更加耦合;且不说使用 Visual-Studio 安装 C/…...
Java中的ZooKeeper是什么?
Java中的ZooKeeper是一个开源的分布式协调服务,它可以帮助我们管理分布式系统中的数据和配置信息。ZooKeeper是由Facebook开发的一个开源项目,它被广泛用于Facebook的分布式系统。 ZooKeeper的名称来源于动物园管理员(Zookeeper)…...
【数学】CF1796 C
Problem - 1796C - Codeforces 题意: 思路: 模拟一下样例可以发现一些规律 Code: #include <bits/stdc.h>#define int long longusing i64 long long;constexpr int N 1e6 10; constexpr int mod 998244353;void solve() {int l…...
SCI论文中字体和图片字体大小的要求
SCI论文中字体和图片字体大小的要求 文章目录 1. American Chemical Society(ACS)要求2. Nature要求 1. American Chemical Society(ACS)要求 https://www.zhihu.com/question/380612293?utm_id0 2. Nature要求...
react-dnd的使用
介绍: React DnD(Drag and Drop)是一个用于实现拖放功能的 React 拓展库。它提供了一组用于构建可拖动和可放置组件的高阶组件和钩子函数。 使用: 安装 react-dnd 和 react-dnd-html5-backend: npm install react-d…...
ELF program/section segment解析
ELF program/section segment解析 1 elf program segment1.1 elf program header1.2 ELF32和ELF64示例1.2.1 ELF32 program segment1.2.2 ELF64 program segment 1.3 elf program segment数据流向图 2 elf section2.1 eld section header2.2 ELF32和ELF64示例2.2.1 ELF32 secti…...
【golang】库源码文件
库源码文件是不能被直接运行的源码文件,它仅用于存放程序实体,这些程序实体可以被其他代码使用(只要遵从Go语言规范的话)。 这里的“其他代码”可以与被使用的程序实体在同一个源码文件内,也可以在其他源码文件&#x…...
网络安全(黑客)常用工具(附配套资料+工具安装包)
几十年来,攻击方、白帽和安全从业者的工具不断演进,成为网络安全长河中最具技术特色的灯塔,并在一定程度上左右着网络安全产业发展和演进的方向,成为不可或缺的关键要素之一。 话不多说,2022年全球白帽常用工具排行榜…...
WebDAV之π-Disk派盘+Joplin
Joplin是一个优秀的开源笔记,可以组织到笔记本中的大量笔记和文本编辑器中进行复制,标记和修改。支持Evernote的笔记直接导入到Joplin应用程序中。Joplin还支持各种云服务同步,包括Dropbox、OneDrive、WebDAV或文件系统,方便对其进行检查、备份和移动。该应用程序可用于Win…...
Unity-UGUI优化策略
界面出栈规则: 界面目录导航、策划界面回退需求造成界面套娃问题,夹带一系列层级问题,应该和策划进行友好沟通,避免界面不合理的出栈入栈规则 overdraw: 尽量减少同屏 半透明物体渲染 Unity 之 UGUI优化(…...
【练】Linux中用共用体(联合体)的方式,判断本机的字节序
方法一:共用体 #include <stdio.h> union Byte {unsigned int a;char c; }; int main(int argc, const char *argv[]) {union Byte endianness;endianness.a0x87654321;printf("endianness.c%#x\n",endianness.c); if(0x21 endianness.c)pr…...
WebRTC | 音视频直播客户端框架
端到端通信互动技术可分解为以下几个技术难点:客户端技术、服务器技术、全球设备网络适配技术和通信互动质量监控与展示技术。 一、音视频直播 音视频直播可分成两条技术路线:一条是以音视频会议为代表的实时互动直播;另一条是以娱乐直播为代…...
flutter开发实战-实现marquee根据文本长度显示文本跑马灯效果
flutter开发实战-实现marquee文本跑马灯效果 最近开发过程中需要marquee文本跑马灯效果,这里使用到了flutter的插件marquee 效果图如下 一、marquee 1.1 引入marquee 在pubspec.yaml中引入marquee # 跑马灯效果marquee: ^2.2.31.2 marquee使用 marquee使用也是…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
