Here is an example of what we’re gonna build today.
你看过Apple iOS的视差壁纸吗?如果你在iOS的墙纸设置中启用“透视缩放”,你会发现你的主屏幕将根据设备的倾斜/位置做出视觉响应。这虽然是简单的视觉上的把戏,却令人印象深刻。
以下是我们今天要构建的示例。
注意:本文中所有图像都在FAIR USE内使用,并且实际文件不外传。
开始啦…
我们将使用Flutter的官方传感器插件来获取设备的倾斜/旋转。
只需将以下内容作为你的依赖项,然后在项目文件夹中运行“pub get”就能完成简单的安装了。
sensors: ^0.4.2+6
注意:需检查并使用最新版本。在写本文时,我使用了以上叙述的版本。
现在我们需要两张图像,一张用作星空背景,另一张用于行星。我们要确保行星的图像是透明的,因为我们要将它堆叠在背景图像的顶部。
我们将用Stack小部件来放置图像。将小部件放在堆栈里的图像中。
对于设备的倾斜/旋转检测,我们将使用运动事件来获取x、y轴上的加速度。
开始编写
class PerspectiveZoomDemo extends StatefulWidget {
PerspectiveZoomDemo({
Key key,
}) : super(key: key);
@override
_PerspectiveZoomDemoState createState() => _PerspectiveZoomDemoState();
}
class _PerspectiveZoomDemoState extends State<PerspectiveZoomDemo> {
AccelerometerEvent acceleration;
StreamSubscription<AccelerometerEvent> _streamSubscription;
int planetMotionSensitivity = 4;
int bgMotionSensitivity = 2;
@override
void initState() {
_streamSubscription = accelerometerEvents.listen((AccelerometerEvent event) {
setState(() {
acceleration = event;
});
});
super.initState();
}
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Center(
child: Stack(
children: <Widget>[
Positioned(
top: acceleration.y * bgMotionSensitivity,
bottom: acceleration.y * -bgMotionSensitivity,
right: acceleration.x * -bgMotionSensitivity,
left: acceleration.x * bgMotionSensitivity,
child: Align(
child: Image.asset(
"assets/images/bg.jpg",
height: 1920,
fit: BoxFit.fitHeight,
),
),
),
Positioned(
top: acceleration.y * planetMotionSensitivity,
bottom: acceleration.y * -planetMotionSensitivity,
right: acceleration.x * -planetMotionSensitivity,
left: acceleration.x * planetMotionSensitivity,
child: Align(
child: Image.asset(
"assets/images/earth_2.png",
width: 250,
),
),
),
],
),
),
);
}
}
说明:
我们已经订阅了设备的accelerometer events,并且正在乘数bgMotionSensitivity和planetMotionSensitivity的基础上更改背景和行星图像的位置。
为什么bgMotionSensitivity低于planetMotionSensitivity?
答:这是因为视差效果的工作原理,即离你较远的对象要比离你近的对象移动得慢。
结果:
行星和背景对设备运动的响应及时,但是…
如果对它进行试运行,你就会发现它非常不稳定并且断断续续的。
那我们在哪里做错了呢?
问题及解决方案:
这里的问题是加速度计的事件太快了,并且值变化得也很快,因此每当值突然变化时,我们的动画就会停顿。
我们需要添加某种过渡延迟来填补这些快速变化的值。幸运的是,flutter提供了一个名为AnimatedPositioned的小部件,它可以在Stack小部件中使用。
解决方案:
AnimatedPositioned(
duration: Duration(milliseconds: 250),
top: acceleration.y * bgMotionSensitivity,
bottom: acceleration.y * -bgMotionSensitivity,
right: acceleration.x * -bgMotionSensitivity,
left: acceleration.x * bgMotionSensitivity,
child: Align(
child: Image.asset(
"assets/images/bg.jpg",
height: 1920,
fit: BoxFit.fitHeight,
),
),
),
AnimatedPositioned(
duration: Duration(milliseconds: 250),
top: acceleration.y * planetMotionSensitivity,
bottom: acceleration.y * -planetMotionSensitivity,
right: acceleration.x * -planetMotionSensitivity,
left: acceleration.x * planetMotionSensitivity,
child: Align(
child: Image.asset(
"assets/images/earth_2.png",
width: 250,
),
),
),
说明:
我们已用AnimatedPositioned替换了Positioning,并设置了一些延迟(以毫秒为单位)以创建平滑的过渡效果。
结果:
它就像漂浮在屏幕中一样流畅。
这可以用作登录或介绍屏幕的良好背景。
原文作者 Abhi Tripathi
原文链接 https://abhimortal6.medium.com/flutter-smooth-parallax-effect-for-login-and-intro-screens-10bf42073741