0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是PAG动效组件 PAG动效方案使用总结

程序员cxuan 来源:程序员cxuan 2023-04-23 18:24 次阅读

近几年能明显感觉到,互联网产品已经越来越离不开动效了:不管是APP里会动的加载动画UI,还是直播间里华丽的礼物,都需要经历动效上线的过程。而负责这些动效上线的前端同学应该有过这样的体验:各种加班写代码上线动画效果,并且在动效还原过程中反复和设计师联调效果。

最近接触到一个开源项目可以帮助大家解决这个问题,它就是PAG动效组件。

PAG 简介:认识 PAG动效

PAG是来自腾讯的一套完整的动画工作流解决方案,助力于将 AE 动画方便快捷的应用于各平台终端。PAG 的流程图下图所示,设计师在 AE 上设计出动画后,可以通过导出插件导出 pag 文件,同时 PAG 提供了桌面端预览工具,支持实时预览效果,在确认效果后,通过运行配置上线,各平台终端可以通过 PAG SDK 加载渲染 PAG 动画。

9bbf98ce-d7d5-11ed-bfe3-dac502259ad0.png

img

PAG 特点及优势 :和其他动效上线方案相比,它强在哪里

● 开源项目:无需担心团队维护问题。

● 文件更小:PAG采用针对 AE 时间轴属性设计的二进制文件编码器,能够使用动态比特位紧凑存储,冗余信息极少,文件体积最小,解码速度最快,且支持单文件集成图片和音频等外部资源。

● 全 AE 特性支持:在纯矢量的导出模式下,无论是哪种实现方案,在众多的 AE 特性面前,都只支持将有限的 AE特性导出渲染,PAG 方案提供了 BMP 预合成的解决方案,支持将特定图层截图导出成透明视频,实现了对于所有 AE 特性导出的支持。

● 运行时编辑:PAG 不仅仅支持文本图层的文本编辑、图片图层的占位图替换,还支持图层级别的增加、删除及更改渲染位置,实现原子素材的自由组合,典型的应用场景就是视频模版和游戏战报,一个模版中由多个 pag 有机组合在一起。

● 渲染架构:相对于 Lottie 、SVGA 依赖于平台端相关的渲染接口,PAG 使用了跨平台一致的 C++ 架构,平台层面仅仅提供渲染环境,渲染的主体位于 C++ 层,可以实现跨平台的渲染一致性。

● 支持的平台更多:相比 Lottie 支持 AndroidiOS、Web 和 macOS, SVGA 支持 Android、iOS、Web,PAG 实现了 Android、iOS、Web、macOS、Windows、Linux 和 微信小程序,支持的平台更多。

这里放一张对比图,大家就一目了然了:

9bcba0c4-d7d5-11ed-bfe3-dac502259ad0.png

img

想进一步了解也可以去开源地址:https://github.com/Tencent/libpag

PAG 使用:核心类分析及常用方法解读

在浏览过开源地址后,这里帮大家整理出核心类的分析:

分析
PAGLayer PAG 的渲染图层,PAG 是一个树状结构,PAGLayer 相当于树状结构中的叶子节点。PAG 对外暴露的渲染图层包括 PAGImageLayer (图片图层)、PAGTextLayer (文本图层)、PAGSolidLayer(实色图层),只有这些图层可以二次改编辑。PAGLayer 主要提供了以下能力:以 C++ 层接口为例 ( PAG 的对外接口保持各平台一致性),通过 setMatrix 可以控制图层的位移、缩放和扭曲,通过 setVisible 控制图层的显示与隐藏,通过 localTimeToGlobal 获取该图层相对于主渲染时间轴的具体时间,通过 setStartTime 设置图层相对于主时间轴的开始时间,通过设置 setExcludedFromTimeline 可以控制该图层渲染是否脱离主时间轴由接入方控制。
PAGImageLayer PAGImageView 为图片图层,支持通过 replaceImage 的方法替换默认占位图,同时支持通过 imageBytes 获取默认占位图的数据。它支持用户自己创建,支持指定开始时间和时长,典型的应用场景中将一个外部视频添加到 pag 渲染数据。
PAGTextLayer PAGTextLayer 为文本图层,支持用户修改默认的文本信息、文本颜色、更换字体、字体大小等。为了方便修改文本数据,C++ 封装了 TextDocument 类,支持修改文本的排版、斜体、描边信息等,对应 iOS、Android 平台的 PAGText 类。
PAGSolidLayer PAGSolidLayer 为实色图层,支持修改实色图层的颜色
PAGCompostion PAGComponsition 是渲染树中的容器,继承于 PAGLayer,可以包含多个 PAGLayer,支持用户自己创建,支持增加、删除、更换渲染顺序,支持通过图层名称获取该名称对应的图层。
PAGFile PAGFile 继承于 PAGComposition,不支持自己创建,通过加载 pag 文件获得,相对比 PAGComposition,PAGFile 增加了替换文本图层和图片图层内容的接口,因此如果需要编辑文本图层和图片图层的内容,一方面可以通过图层自身的接口,另一方面可以通过 PAGFile 的接口。
PAGSurface PAGSurface 是 PAG 的渲染画布。PAGSurface 的创建, iOS 平台可以通过 CVPixelBufferRef、尺寸(内部同样创建的是 CVPixelBufferRef),Android 平台可以通过 Surface、SurfaceTexture、TextureID、尺寸等创建,不同的创建方法对应不同的应用场景。PAGSurface 提供了获取单帧渲染数据的接口,支持获取 BGRA 数据、CVPixelBufferRef 和Bitmap。
PAGPlayer PAG 的播放控制类,持有 PAGSurface 和 PAGComposition, 可以通过 setProgress 控制渲染进度, flush 完成当前帧的渲染,可以通过 getBounds 接口获取各 PAGLayer 相对于 PAGSurface 渲染画布的位置信息, 通过 getLayersUnderPoint 获取特定位置下的所有图层。PAGComposition、PAGSurface、PAGPlayer 为 PAG 的三个组件,PAGComposition 提供渲染数据,PAGSurface 提供渲染画布,PAGPlayer 控制渲染进度。在视频后编辑场景,这种使用方式经常被用到。
PAGView 主要使用在 UI 动画场景,存在 Android、iOS、macOS、Web、微信小程序等平台,iOS 平台继承于 UIView, Andoroid 平台继承于 TextView, PAGView 支持通过本地路径 和 PAGComposition 加载, 调用 play 方法进行播放,内部有一个定时器,同时也提供了 PAGViewListener 的接口监听动画播放的状态,PAGView 内部实现了 PAGPlayer、PAGSurface、PAGComposition 的封装处理。
PAGDecoder PAGDecoder 目前存在于 iOS 和 Android 平台, 用于获取 pag 文件的渲染数据,支持通过 PAGComposition 创建,渲染的尺寸和 PAGCompositon 的尺寸一致,同时增加 sacle 参数支持用户设置渲染尺寸,通过 maxFrameRate 的参数设置最大渲染帧率。在数据读取层面,支持获取数据为 UIImage 、Bitmap 和 RGBA 数据。
PAGImageView PAGImageView 主要应用于 UI 列表以及页面中含有多个 pag 文件同时渲染的场景。这些场景使用 PAGView 实现时,页面中需要含有多个 PAGView,每一个 PAGView 都需要有一个 GPU 的渲染环境,任何一个 GPU 渲染的方案都会有一个初始的屏幕缓冲区开销,从而造成 内存占用的增加。PAGImageView 增加了磁盘缓存的功能,针对渲染过的内容,都会缓存到本地,当所有帧的数据缓存完成后,就会销毁 PAG 的渲染环境,剩余的就是磁盘数据的读取,实现了pag 文件渲染与素材的无关性。如果 pag 文件的相关内容没有被编辑过(如编辑文本、替换占位图等),下次加载就会直接读取缓存数据,无需创建 PAG 渲染环境。PAGImageView 的缓存支持两种模式:全磁盘和全内存, 默认为全磁盘模式,此时内存占用是最小的,CPU 占用相对较低,全内存模式的 CPU 占用最低,但内存占用较高,适用于对 CPU 占用要求较高、PAG 文件帧数较少的场景。

这些PAG常用方法解读也能帮助大家使用起来更轻松:

PAG 运行时编辑

PAG 的运行时编辑主要分为两类:1)修改文本图层的文本信息、替换图片图层中的占位图、修改实色图层中的颜色

//C++
std::shared_ptrReplaceImageOrText(){
autopagFile=pag::Load("../../assets/test2.pag");
if(pagFile==nullptr){
returnnullptr;
}
for(inti=0;i< pagFile->numImages();i++){
autopagImage=pag::FromPath("../../assets/scene.png");
pagFile->replaceImage(i,pagImage);
}

for(inti=0;i< pagFile->numTexts();i++){
autotextDocumentHandle=pagFile->getTextData(i);
textDocumentHandle->text="hah哈哈哈哈哈";
pagFile->replaceText(i,textDocumentHandle);
}
returnpagFile;
}

2)渲染树编辑

渲染树编辑指的是通过使用 PAGComposition 的相关接口,完成多个图层、多个 pag 文件的自由组合。具体如何使用可以参考下面的代码:

//以OC版本为例
-(PAGComposition*)makeComposition{
PAGComposition*compostion=[PAGCompositionMake:self.view.bounds.size];
floatitemWidth=self.view.bounds.size.width/5;
floatitemHeight=100;
for(inti=0;i< 20; i++) {
        PAGFile* pagFile = [self getPAGFile:i / 5 clume:i % 5 name:[NSString stringWithFormat:@"%d", i] itemWidth:itemWidth itemHeight:itemHeight];
        [compostion addLayer:pagFile];
    }
    return compostion;
}

- (PAGFile*)getPAGFile:(int)row clume:(int)colume name:(NSString*)name itemWidth:(float)itemWidth itemHeight:(float)itemHeight {
    PAGFile* pagFile = [PAGFile Load:[[NSBundle mainBundle] pathForResource:name ofType:@"pag"]];
    if (pagFile) {
        float scaleX = itemWidth * 1.0f / [pagFile width];
        CGAffineTransform transform = CGAffineTransformMakeScale(scaleX, scaleX);
        CGAffineTransform tranflate = CGAffineTransformMakeTranslation(itemWidth * colume, row * itemHeight + 150);
        transform = CGAffineTransformConcat(transform, tranflate);
        [pagFile setMatrix:transform];
        [pagFile setStartTime:0];
        [pagFile setDuration:10000000];
    }
    return pagFile;
}

PAG UI场景及列表播放

当一个页面中含有多个pag 文件时,如果使用多个 PAGView,由于每一个 PAGView 都需要一个独立的渲染环境,内存和 CPU 占用相对较高,推荐的处理方法有两种:

1)通过使用 PAG 的组合模式用将多个 PAG 文件添加到同一个 PAGComposition 中,具体使用方法见运行时编辑,从而将多个渲染环境缩减到一个渲染环境,降低内存和 CPU 占用;

2)对于一些 UI 列表场景,需要有多个 View 的存在, pag 文件无法添加到一个 PAGComposition 中,此时可以使用 PAGImageView

//以OC版本为例
#import

#defineWIDTH100

@interfacePAGCell:UITableViewCell
@property(nonatomic,strong)PAGImageView*pagImageView;
@property(nonatomic,strong)NSString*filePath;
@end

@implementationPAGCell

-(instancetype)initWithStyle:(UITableViewCellStyle)stylereuseIdentifier:(NSString*)reuseIdentifier{
if(self=[superinitWithStyle:stylereuseIdentifier:reuseIdentifier]){
self.pagImageView=[[PAGImageViewalloc]initWithFrame:CGRectMake(20,0,WIDTH,WIDTH)];
[self.contentViewaddSubview:self.pagImageView];
}
returnself;
}

-(void)setFilePath:(NSString*)filePath{
if([filePathlength]>0){
[self.pagImageViewsetPath:filePath];
[self.pagImageViewsetCurrentFrame:0];
[self.pagImageViewsetRepeatCount:-1];
[self.pagImageViewplay];
}
}

PAG 字体注册

PAG 除了支持修改文本图层的文本信息外,还支持修改字体。具体方法如下:

(1)通过 PAGFont 获取字体的相关信息,然后赋值给 PAGText,使用到的接口如下:

获取字体信息

//C++
/**
*Registersafontrequiredbythetextlayersinpagfiles,sothattheycanberenderedas
*designed.
*/
staticPAGFontRegisterFont(conststd::string&fontPath,intttcIndex,
conststd::string&fontFamily="",
conststd::string&fontStyle="");
/**
*Registersafontrequiredbythetextlayersinpagfiles,sothattheycanberenderedas
*designed.
*/
staticPAGFontRegisterFont(constvoid*data,size_tlength,intttcIndex,
conststd::string&fontFamily="",
conststd::string&fontStyle="");
PAGFont(std::stringfontFamily,std::stringfontStyle)
:fontFamily(std::move(fontFamily)),fontStyle(std::move(fontStyle)){
}

/**
*Astringwiththenameofthefontfamily.
**/
conststd::stringfontFamily;
/**
*Astringwiththestyleinformation—e.g.,“bold”,“italic”.
**/
conststd::stringfontStyle;

(2)fontFamlily 和 fontStyle 赋值给 PAGText,PAGText 再填充到 PAGTextLayer 中。

//C++
for(inti=0;i< pagFile->numTexts();i++){
autotextDocumentHandle=pagFile->getTextData(i);
textDocumentHandle->text="hah哈哈哈哈哈";
//Usespecialfont
autopagFont=pag::RegisterFont("../../resources/font/NotoSansSC-Regular.otf",0);
textDocumentHandle->fontFamily=pagFont.fontFamily;
textDocumentHandle->fontStyle=pagFont.fontStyle;
pagFile->replaceText(i,textDocumentHandle);
}

如果使用了特定字体而又没有注册或字体文件中没有包含该字符,PAG 内部(Android、iOS、macOS、Windows 平台)有一个默认字体列表(同时支持外部设置字体回退列表,外部设置时会覆盖默认设置),会回退到 PAG 的默认字体列表中,此时使用那种字体对于业务方而言是不确定的。

//C++
/**
*Resetsthefallbackfontnames.Itshouldbecalledonlyoncewhentheapplicationisbeing
*initialized.
*/
staticvoidSetFallbackFontNames(conststd::vector&fontNames);

/**
*Resetsthefallbackfontpaths.Itshouldbecalledonlyoncewhentheapplicationisbeing
*initialized.
*/
staticvoidSetFallbackFontPaths(conststd::vector&fontPaths,
conststd::vector&ttcIndices);

PAG 视频编辑场景

在视频编辑场景,使用的不是 PAGView,而是 PAGPlayer、PAGSurface 和 PAGComposition。

PAGSurface 可以通过 CVPixelBufferRef 或纹理创建,方便快捷的与视频后编辑中的 CVPixelBuffer 或 纹理进行整合。同时 PAGImage 也支持通过 CVPixelBufferRef 或 纹理创建,通过 PAGPlayer 控制播放进度,将视频内容填充进图片图层的占位图。

//OC
/**
*CreatesaPAGImageobjectfromthespecifiedCVPixelBuffer,returnnulliftheCVPixelBufferis
*invalid.
*/
+(PAGImage*)FromPixelBuffer:(CVPixelBufferRef)pixelBuffer;

//java
publicstaticPAGImageFromTexture(inttextureID,inttextureTarget,intwidth,intheight);

publicstaticPAGImageFromTexture(inttextureID,inttextureTarget,intwidth,intheight,booleanflipY);

PAG 软解注入

为什么会有软解注入?PAG 的导出方式中支持 BMP 预合成导出,在 pag 文件中,如果含有 BMP 预合成,一个 BMP 预合成相当于一个视频,视频则需要解码。在 PAG SDK 中默认使用硬件解码,但硬件解码存在两个问题:

1)移动端硬件解码器的瞬时存在数目是有限制的,不能无限的创建,如果创建硬件解码器的数目超过限制,就会出现解码器创建失败的情况,在视频编辑场景中需要关注;

2)Android 平台由于机型兼容性、碎片化验证,不能保证所有的机型都能硬件解码成功,因此 Android 平台软解是必须的。

于是,在提供的制品库中, iOS 平台由于没有兼容性的问题,默认是不带软解的,Android 提供了两个包,普通的包默认是内置软解的,noffavc 的包是没有内置软解的。

具体怎么注入软解呢:Android 平台可以选择完整制品库,iOS 平台可以引入 ffavc。

pod'ffavc'

通过如下方法完成软件解码器的注册:

//OC
-(void)registerSoftwareDecoder
{
//注册软件解码器工厂指针
autofactory=ffavc::GetHandle();
[PAGVideoDecoderRegisterSoftwareDecoderFactory:(void*)factory];
}

如果接入方自己的 APP 中已经内置了软解库,可以通过外部注入的方式注入软解。

PAG 官网提供了下面这个软解注入接口,需要业务方基于自己的解码器实现,PAG BMP 预合成中的视频编码格式为 h264。

https://github.com/libpag/ffavc/blob/main/vendor/libpag/include/pag/decoder.h

具体的实现方式可以参考:

ffavc/FFAVCDecoder.cpp at main · libpag/ffavc · GitHub

然后自己通过上面提到的方式注入软解。

PAG 服务端渲染

和 Lottie、SVGA 不同的是,PAG 支持服务端渲染,尽管 PAG 的渲染依赖 OpenGL 环境,但 服务端却可以继续使用 CPU 服务器。具体实现层面,PAG 通过 swiftshader 在 CPU 服务器上构建出了 OpenGL 环境,使得 pag 文件可以在 CPU 环境中正常渲染。

在服务端的具体使用如下,获取到的是 BGRA 的数据,该数据可以用于视频编码。

//C++
autopagFile=pag::Load("../../assets/test2.pag");
autopagSurface=pag::MakeOffscreen(pagFile->width(),pagFile->height());
if(pagSurface==nullptr){
printf("---pagSurfaceisnullptr!!!
");
return-1;
}
autopagPlayer=newpag::PAGPlayer();
pagPlayer->setSurface(pagSurface);
pagPlayer->setComposition(pagFile);

autototalFrames=TimeToFrame(pagFile->duration(),pagFile->frameRate());
autocurrentFrame=0;

intbytesLength=pagFile->width()*pagFile->height()*4;

while(currentFrame<= totalFrames) {
    pagPlayer->setProgress(currentFrame*1.0/totalFrames);
autostatus=pagPlayer->flush();

//PAG渲染数据读取
autodata=newuint8_t[bytesLength];
pagSurface->readPixels(pag::BGRA_8888,pag::Premultiplied,data,
pagFile->width()*4);
delete[]data;

currentFrame++;
}

deletepagPlayer;

开始使用 :如何接入

接入使用分为开发部分和设计部分,这里分别为大家介绍下:

(1) 开发者——接入SDK

在PAG的Github Wiki中有非常详细的接入指引(包括Android、iOS、Web等平台的接入方法和范例工程)

9bdb5640-d7d5-11ed-bfe3-dac502259ad0.png

img

(2)设计师——下载导出插件和预览工具

设计师想要使用PAG,只需在官网下载预览工具 PAGViewer和 AE 导出插件即可//pag.art/docs/install.html

9be69e24-d7d5-11ed-bfe3-dac502259ad0.png

img

整体看来,PAG的核心价值如下:

上线难点 传统方案痛点 PAG动效价值
研发成本 每个动效都需要研发通过代码来还原,需要大量的研发人力持续投入,由于研发人力有限,导致这个流程无法批量化生产素材。 研发只有一次性接入 SDK的成本,在后续整个素材生产流程都无需研发人力介入。整套工作流不在受制于研发的人力瓶颈,就能够开放给更多的设计师使用,批量化的进行素材生产。
生产周期 设计师和研发人员的联调成本高,效果还原度需要反复确认,中间产生较长的上线周期,拖延产品运营节奏。 由于砍掉了研发成本,最耗时的研发和设计的联调环节也不存在了。设计师可以所见即所得地生产素材,极大地缩短了生产周期,能够快速响应运营热点。
动效视觉 AE里有很多复杂动效,使用纯代码还原起来非常困难,设计师只能不断简化效果以达到跟开发成本的平衡,导致上线的视觉效果大打折扣。 PAG的SDK完全还原了AE整个动效的渲染系统,接入一次,设计师就可以充分利用AE动效的原子能力,组合出无限的视觉动效,不用因为代码还原成本的问题而打折扣。

据官网显示已经有很多头部应用接入使用(如微信、王者荣耀、小红书、知乎等),稳定性应该很有保证,如果有动效上线相关业务的朋友非常值得试试。
编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • PAG
    PAG
    +关注

    关注

    0

    文章

    2

    浏览量

    6881
  • C++
    C++
    +关注

    关注

    22

    文章

    2108

    浏览量

    73634
  • SDK
    SDK
    +关注

    关注

    3

    文章

    1036

    浏览量

    45918

原文标题:PAG 动效方案使用总结

文章出处:【微信号:cxuangoodjob,微信公众号:程序员cxuan】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    设计的这些设计流程你知道吗

    交互设计师想要认真和你聊聊设计
    发表于 02-25 06:39

    求一个主流功率等级的高能OBC方案

    碳化硅(SiC) MOSFET、超级结MOSFET、IGBT和汽车功率模块(APM)等广泛的产品阵容乃至完整的系统方案,以专知和经验支持设计人员优化性能,加快开发周期。本文将主要介绍针对主流功率等级的高能OBC方案
    发表于 11-23 11:10

    app图标在openharmony的源码上哪里实现的?

    openharmony点击一个app图标的之后,应用会从左上角一点点放大直至铺满屏幕;我想问一下这个是在openharmony的源码上的哪里实现的?
    发表于 06-10 11:01

    TMS320F28035PAG-64pin电路图

    TMS320F28035PAG-64pin电路图
    发表于 11-02 10:59 43次下载

    怎样才能提高APP可用性的设计

    简评:本文将市面上最常被使用的进行了一次总结并逐条阐明这些设计背后的原理,plus 每条原理后面我都会为朋友们选出一些大家最常用的 App 作为例子,顺手打开就能体验啦。 缓(E
    发表于 09-25 17:13 0次下载
    怎样才能提高APP可用性的<b class='flag-5'>动</b><b class='flag-5'>效</b>设计

    微星34寸曲面带鱼屏PAG341CQR高清图集

    日前,微星发布了一款专业电竞显示器,型号为“PAG341CQR”,其最大亮点就是配备了原色量子点显示技术,目前京东售价3499元。
    的头像 发表于 11-21 10:27 6559次阅读

    小米:MIUI 12.5 光锥架构将全面升级

    根据小米官方的消息,12 月 28 日的小米 11 系列发布会上,除了新机之外,MIUI 12.5 也将亮相,今日小米官方不断对新系统预热。 根据小米手机最新的预热消息,“MIUI 光锥架构全面
    的头像 发表于 12-28 10:34 2070次阅读

    全新MIUI 12.5系统采用新一代光锥架构

    小米发布会如期而至,小米方面首先向大家展示了全新的MIUI 12.5系统,小米为新系统升级了新一代的光锥、超级壁纸等视,手机整体的视觉效果进一步升级。
    的头像 发表于 12-29 09:29 2920次阅读

    多场景下的智能手机人机交互动设计体验

    智能手机上,无处不在,是手机操作过程中呈现和使用频率最高的功能之一。针对智能手机动设计的基本原则、方法和准则展开研究,就设计的体验
    发表于 06-21 16:57 24次下载

    华为图像服务场景Java示例代码

    简介 场景服务提供基础和高级,帮助您实现图片内容高效再生产。本示例代码对华为图像服务
    发表于 03-23 11:06 0次下载

    在OpenHarmony上实现弹性的方法

    在动画开发场景中,经常用到弹性效果,尤其在拖拽某个对象时经常伴随弹性
    的头像 发表于 06-11 15:12 743次阅读
    在OpenHarmony上实现弹性<b class='flag-5'>动</b><b class='flag-5'>效</b>的方法

    如何在OpenHarmony上实现​翻页呢?

    翻页是应用开发中常见的场景,常见的如书籍翻页、日历翻页等。
    的头像 发表于 06-11 15:15 697次阅读
    如何在OpenHarmony上实现​翻页<b class='flag-5'>动</b><b class='flag-5'>效</b>呢?

    OpenHarmony实战开发-如何实现组件动画。

    ArkUI为组件提供了通用的属性动画和转场动画能力的同时,还为一些组件提供了默认的动画效果。例如,List的滑动动,Button的点击
    的头像 发表于 04-28 15:49 621次阅读
    OpenHarmony实战开发-如何实现<b class='flag-5'>组件</b>动画。

    鸿蒙ArkTS声明式组件:LoadingProgress

    用于显示加载组件
    的头像 发表于 06-24 16:53 616次阅读
    鸿蒙ArkTS声明式<b class='flag-5'>组件</b>:LoadingProgress

    鸿蒙ArkTS容器组件:Refresh

    可以进行页面下拉操作并显示刷新的容器组件
    的头像 发表于 07-11 16:11 507次阅读