啥?Flutter也能整3D了吗?我靠,竟然是这样的操作
Posted 阿 T
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了啥?Flutter也能整3D了吗?我靠,竟然是这样的操作相关的知识,希望对你有一定的参考价值。
前言:在网上看到了一个3D展示的效果,属实强😎,于是我准备拿Flutter复刻一个,可是晚上找了半天也没有发现Flutter怎么使用3D模型,但是直到我看了这个节目,话不多说,先上效果图!
灵感来源:https://www.youtube.com/watch?v=FCyoHclCqc8&t=149s
视频讲解了很多复杂UI的处理制作
源码在文章的最后哦(点点赞呗,各位)~
效果图:
先分析一下原理,分为3个部分:
1.背景的旋转处理
2.文字的旋转动画处理
3.吉他(贝斯,写文章的时候才发现不是吉他)的旋转处理与吉他背景阴影的处理
1.背景的旋转处理
在复杂的动画中,常用的便是:Transform,Stack,AnimationController
这里也是一样:
_buildBackground() => Positioned.fill(
top: -_extraHeight,
bottom: -_extraHeight,
child: AnimatedBuilder(
animation: _animator,
builder: (context, widget) => Transform.translate(
offset: Offset(_maxSlide * _animator.value, 0),
//重点是这里
child: Transform(
transform: Matrix4.identity() //单位矩阵,倾斜的角度
..setEntry(3, 2, 0.001)
..rotateY((pi / 2 + 0.1) * -_animator.value),
alignment: Alignment.centerLeft, //相对于坐标系原点的对齐方式
child: widget,
),
),
//以下就是普通的Widget
child: Container(
color: Color(0xffe8dfce),
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
//Fender word
Positioned(
top: _extraHeight + 0.1 * _screen.height,
left: 80,
child: Transform.rotate(
angle: 90 * (pi / 180),
alignment: Alignment.centerLeft,
child: Text(
"HELLO",
style: TextStyle(
fontSize: 100,
color: Color(0xFFc7c0b2),
shadows: [
Shadow(
color: Colors.black26,
blurRadius: 5,
offset: Offset(2.0, 0.0),
),
],
fontWeight: FontWeight.w900,
),
),
),
),
//给切换时加上一个黑色的背景动画,使动画更加立体
AnimatedBuilder(
animation: _animator,
builder: (_, __) => Container(
color: Colors.black.withAlpha(
(150 * _animator.value).floor(),
),
),
),
],
),
),
),
);
2.文字的旋转动画处理
- 顶部文字
//适配异形屏 SafeArea( child: AnimatedBuilder( animation: _animator, builder: (_, __) return Transform.translate( //平移动画 offset: Offset((_screen.width - 60) * _animator.value, 0), child: ...); ) )
-
底部文字
这里的平移动画需要跟随背景动画,在此基础上加了一个透明度,一个平移动画,更加立体
Opacity( //透明度 opacity: 1 - _animator.value, //与背景动画相同,在其基础上加了一个平移动画 child: Transform.translate( offset: Offset((_maxSlide + 50) * _animator.value, 0), child: Transform( transform: Matrix4.identity() ..setEntry(3, 2, 0.001) ..rotateY((pi / 2 + 0.1) * -_animator.value), alignment: Alignment.centerLeft, child: widget, ), ), )
-
左侧文字
此处的文字动画与上面相差不大,只在参数上有区别
Transform.translate( offset: Offset(_maxSlide * (_animator.value - 1), 0), child: Transform( transform: Matrix4.identity() ..setEntry(3, 2, 0.001) ..rotateY(pi * (1 - _animator.value) / 2), alignment: Alignment.centerRight, child: widget, ), )
3.贝斯的旋转处理与贝斯背景阴影的处理
这部分是本文的重点,先说一下3D效果的原理。我在这里找了120张贝斯的图,分别是每移动一点所对应的图片,当移动时,传入移动的距离,显示不同的图片
在这里封装了一个ImageSequenceAnimator,有个插件叫image_sequence_animator,但是功能不满足我自定义的需求,就把它的源码拿出来改了改。
注意事项:图片的命名
在这里只给大家分析最重要的点了,源代码中我注释的很全~
-
对于图片名称的补齐:
String _getSuffix(String value) while (value.length < suffixCount) value = "0" + value; return value;
-
获取到图片的路径:
String _getDirectory() return folderName + "/" + fileName + _getSuffix((suffixStart + _previousFrame).toString()) + "." + fileFormat;
-
UI处理:
@override Widget build(BuildContext context) if (widget.frame != null) if (currentFrame == null || widget.frame != _previousFrame || colorChanged) colorChanged = false; _previousFrame = widget.frame; if (_previousFrame < frameCount) currentFrame = Image.asset( _getDirectory(), color: color, gaplessPlayback: true, ); return currentFrame; return ValueListenableBuilder( builder: (BuildContext context, int change, Widget cachedChild) if (currentFrame == null || animationController.value.floor() != _previousFrame || colorChanged) colorChanged = false; _previousFrame = animationController.value.floor(); if (_previousFrame < frameCount) currentFrame = Image.asset( _getDirectory(), color: color, gaplessPlayback: true, ); //currentFrame是Image return currentFrame; , valueListenable: changeNotifier, );
-
使用方法:
ImageSequenceAnimator( "assets/guitarSequence", //folderName "", //fileName 1, //suffixStart 4, //suffixCount "png", //fileFormat 120, //frameCount fps: 60, isLooping: false, isBoomerang: true, isAutoPlay: false, frame: (_objAnimator.value * 120).ceil(), // fullPaths: [(_objAnimator.value * 120).ceil().toString()],//官方插件的使用 )
-
贝斯阴影处理
Positioned( //无需动画,用Stack叠在贝斯照片下面就行 top: _extraHeight + 0.13 * _screen.height, bottom: _extraHeight + 0.24 * _screen.height, left: _maxSlide - 0.41 * _screen.width, right: _screen.width * 1.06 - _maxSlide, child: Column( children: <Widget>[ //绘制了一个贝斯的形状 Flexible( child: FractionallySizedBox( widthFactor: 0.2, child: Container( decoration: BoxDecoration( boxShadow: [ BoxShadow( blurRadius: 50, color: Colors.black38, ) ], borderRadius: BorderRadius.circular(50), ), ), ), ), Flexible( child: Container( decoration: BoxDecoration( boxShadow: [ BoxShadow( blurRadius: 50, color: Colors.black26, ) ], borderRadius: BorderRadius.circular(50), ), ), ), ], ), ),
Flutter复杂的3D就这样很简单就完成啦~
以上是关于啥?Flutter也能整3D了吗?我靠,竟然是这样的操作的主要内容,如果未能解决你的问题,请参考以下文章
金九银十,我靠这一份PDF文档面试BAT,没想到竟然收到了5个offer
备战金九银十,我靠这一份PDF文档面试BAT,没想到竟然收到了5个offer