Flutter Faux Self App Naked Eye 3D Effect

Overview

github 限制图片大小,失效图片请移步掘金查看:拿去吧你!Flutter 仿自如 App 裸眼 3D 效果

引言

最近看到 自如团队 发布的 自如客APP裸眼3D效果的实现,这个布局确实做得很有趣,越玩越上瘾,感谢自如团队的分享。随即按照自己的思路用 Flutter 实现一遍,来看看最终效果。

banner 样式 全屏样式
IMG_0020.gif IMG_0021.gif

apk 下载可直接运行:https://github.com/fluttercandies/flutter_interactional_widget/blob/main/app-release.apk

本文会着重介绍我在实现过程中的思路和设计,所以无论你是前端 /iOS/Android/Flutter 都可以参考同样的路子去实现。如果有任何问题,也欢迎探讨。


一、整体构思

从效果上可以看出,随着我们设备的旋转,有的部分顺着倾斜方向滑动,有的朝着相反方向,而有的则不动。所以图片上的元素肯定分为不同的图层,旋转设备让图层发生移动即可达到效果。

将图片分为了前、中、后三层,随着手机角度的旋转,中层保持不动,上层顺着旋转方向移动,下层与上层相逆。

(图片来自自如分享)

所以在图片分层之后,这个效果就变成了两步:

1、获取手机的旋转信息

2、根据旋转信息移动不同的图层


二、获取手机的旋转信息

Flutter 中有这样一个插件 sensors_plus ,使用它可以帮助我们获取两个传感器的信息:Accelerometer(加速度传感器)、Gyroscope(陀螺仪)。

传感器.gif

每个传感器提供了一个 Stream ,其发送的事件包含 X、Y、Z 表示手机不同方向的变化的速度。通过对 Stream 的监听,我们便可实时获取相关传感器数据。

这个仓库中也附带了一个体感贪吃蛇的 demo,倾斜设备,小蛇便朝着倾斜方向前进。

贪吃蛇.gif

插件的更多介绍可以查看视频: Flutter Widgets 介绍合集 —— 103. Sensors_plus

我们实现的效果需要根据手机旋转移动图层,自然使用陀螺仪传感器即可:

 gyroscopeEvents.listen(
       (GyroscopeEvent event) {
       // event.x  event.y  event.z
     ································
   },
 ),

回调的 GyroscopeEvent 包含三个属性,x、y、z,分别对应下图三个方向所检测到的旋转速度(单位:弧度/秒)

xyz.png

结合需求来看,我们只需使用 Y 轴(对应图像在水平方向的移动)和 X 轴(对应图像在竖直方向的移动)的数据即可。


三、根据旋转信息移动图层

在网上找了一个 psd 文件,导出图片之后整体长这样:

封面.png

我在 psd 文件中导出 3 个图层,需要注意图片格式要为 .png,这样上一个图层的透明区域不会被填充为白色而遮挡住下一个图层,之后直接使用 Image widget 展示图片即可:

前景 中景(白色的文字,所以看不见) 背景
fore.png mid.png back.png

1、让图层动起来

图片分为三层,我们自然想到使用 Stack 作为容器,依次放入三个图层(Widget)

 // 背景图层
 Widget? backgroundWidget;
 // 中景图层
 Widget? middleWidget;
 // 前景图层
 Widget? foregroundWidget;

图层移动其实很简单,就是去修改每一个图层的偏移量。再观察这个实现效果,会发现随着我们的旋转,图层中的内容好像 出来一样。

所以我们一开始进入时,看到的肯定只是图片的部分区域。我的想法是给每一个图层设置 scale,将图片进行放大。显示窗口是固定的,那么一开始只能看到图片的正中位置。(中层可以不用,因为中层本身是不移动的,所以也不必放大)

image.png

旋转手机修改偏移量,为前景和背景层设置相反的偏移量,便可达到两个图层反向运动的效果。

在计算偏移量的时候还需要考虑两个因素:

1、图层的最大偏移量

图层经过了一定比例的放大,所以存在一个最大的偏移范围,偏移量不能超过这个范围。

image.png

不难看出水平方向上最大偏移计算方法为:(缩放比例-1) * 宽 / 2, 竖直方向同理。

2、前景与背景图层的相对偏移速度

因为前景和背景的缩放比例可能不同,如果两者以 1:1 的相对偏移,可能会出现以下情况。

image-20210729005136818.png 假如 前景缩放是 1.4,背景为 1.8,当显示区域向左移动 2 像素的时候。这时背景层所显示的区域同样向左移动 2 个像素,前景层相反。但这时前景已经达最大的偏移量,不能再继续移动。而背景其实还有区域未能显示,所以可以通过两者的缩放比计算对应的偏移比,保证两个图片都能完整的展示出来。

 // 通过背景偏移计算前景偏移
 Offset getForegroundOffset(Offset backgroundOffset) {
   // 假如前景缩放比是 1.4 背景是 1.8 控件宽度为 10
   // 那么前景最大移动 4 像素,背景最大 8 像素
   double offsetRate = ((widget.foregroundScale ?? 1) - 1) /
       ((widget.backgroundScale ?? 1) - 1);
   // 前景取反
   return -Offset(
       backgroundOffset.dx * offsetRate, backgroundOffset.dy * offsetRate);
 }

这里我通过背景偏移为标准,计算前景偏移,并且在计算背景偏移的之前先考虑了最大偏移范围,这样保证前景和背景都不会发生越界行为。先通过拖拽改变偏移量调用 setState 更新界面,看看图层部分实现的效果:

1627550866693665.gif

背景随着手指滑动而位移,同时前景朝相反的方向移动,当滑动到图层边界时无法继续,整个过程中层保持不动。

2、传感器控制偏移

图层位移实现之后,我们只需要将上面由手指滑动触发的偏移改变为由传感器触发即可。

这里我们来想一个问题,我们设备处于水平状态时,显示区域居中,而当设备倾斜的时候,显示区域移动。

image.png

那么该旋转多少角度达到最大偏移量呢?

所以这里我定义了两个变量:

  double maxAngleX;
  double maxAngleY;

分别表示水平和垂直方向的最大旋转角度。假设 maxAngleX 为 10,表示当你在水平方向旋转设备 10° 度的时候,图像显示到边界了。

有了这个定义我们便可反推出背景层 旋转 1° 的偏移量为:

1/maxAngleX * maxBackgroundOffset.dx,垂直方向同理。

思路就是这样,不过我在实现的时候还遇到了一个棘手的问题:

由于 sensors_plus 插件中提供的是各方向的旋转速度(rad/s),我们改如何计算实际的旋转角度?

其实并不难:旋转弧度 = (旋转速度(rad/s) * 时间),那么这里时间是多少?

看 sensors_plus 插件的安卓端实现,这个插件通过 SensorManager 注册陀螺仪传感器的回调,通过 chanel 将采集到的数据直接传递到 Flutter 侧。

sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);

在安卓端 SensorManager 的采集灵敏度分几种

  • SensorManager.SENSOR_DELAY_FASTEST(0微秒):最快。最低延迟,一般不是特别敏感的处理不推荐使用,该模式可能在成手机电力大量消耗,由于传递的为原始数据,算法不处理好会影响游戏逻辑和UI的性能
  • SensorManager.SENSOR_DELAY_GAME(20000微秒):游戏。游戏延迟,一般绝大多数的实时性较高的游戏都是用该级别
  • SensorManager.SENSOR_DELAY_NORMAL(200000微秒):普通。标准延时,对于一般的益智类或EASY级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象
  • SensorManager.SENSOR_DELAY_UI(60000微秒):用户界面。一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中不使用

不同灵敏度的采集时间不同,sensors_plus 默认是 SENSOR_DELAY_NORMAL 即 0.2S ,实际使用时感觉响应并没那么及时。所以我直接 fork 项目下来,将 SENSOR_DELAY_NORMAL 改为了 SENSOR_DELAY_GAME ,即每次采集时间为 20000微秒(0.02秒)

换算成角度就是:x * 0.02 * 180 / π,再用角度换算背景偏移量,背景偏移量考虑最大偏移范围之后,计算前景,调用 setState 更新界面即可。关键步骤如下:

gyroscopeEvents.listen((event) {
  setState(() {
    // 通过采集的旋转速度计算出背景 delta 偏移
    Offset deltaOffset = gyroscopeToOffset(-event.y, -event.x);
    // 初始偏移量 + delta 偏移 之后考虑越界
    backgroundOffset = considerBoundary(deltaOffset + backgroundOffset);
    // 背景偏移根据缩放比例获取前景偏移
    foregroundOffset = getForegroundOffset(backgroundOffset);
  });
});

四、构造函数说明

InteractionalWidget

属性 说明 是否必选
double width 视窗宽度
double height 视窗高度
double maxAngleX 水平方向最大的旋转角度
double maxAngleY 竖直方向最大的旋转角度
double? backgroundScale 背景层缩放比
double? middleScale 中景层缩放比
double? foregroundScale 前景层的缩放比
Widget? backgroundWidget 背景层 widget
Widget? middleWidget 中景层 widget
Widget? foregroundWidget 前景层 widget

三个图层均非必传,所以你也可以只指定 前景/背景 单一图层的位移。

仓库已上传至 pub 通过依赖:

所有代码皆已上传至 github,其中演示程序 apk 可以直接下载运行,后面这个仓库还会更新一些交互式的小组件,给个点赞、关注、 star 不过分吧~


五、最后

本来是打算接着写网络编程,中途看到 自如客APP裸眼3D效果的实现 于是趁着周末赶紧实现了一下,再次感谢 自如团队 提供这么妙的创意。下一期,还是按照之前的计划,通过 广播/组播的方式实现一个基础的局域网多端群聊服务。

如果你有任何疑问可以通过公众号与联系我,如果文章对你有所启发,希望能得到你的点赞、关注和收藏,这是我持续写作的最大动力。Thanks~

公众号:进击的Flutter或者 runflutter 里面整理收集了最详细的Flutter进阶与优化指南,欢迎关注。

往期精彩内容:

Flutter 进阶优化

Flutter核心渲染机制

Flutter路由设计与源码解析

You might also like...

A custom navigation bar with bubble click effect in Flutter

A custom navigation bar with bubble click effect in Flutter

custom_navigation_bar A custom navigation bar with bubble click effect. Overview This project is inspired by this post from Dribbble and The Boring Fl

Jan 2, 2023

A package provides an easy way to add shimmer effect in Flutter project

flutter_shimmer_widget A package provides an easy way to add shimmer effect in Flutter project Getting Started Animation Example Project There is a ex

Jun 29, 2022

Flutter remote control - The main use of LongPressDraggable and DragTarget to achieve the universal remote control interaction effect.

Flutter remote control - The main use of LongPressDraggable and DragTarget to achieve the universal remote control interaction effect.

Flutter remote control - The main use of LongPressDraggable and DragTarget to achieve the universal remote control interaction effect.

Jan 2, 2023

A Flutter plugin to apply a gyroscope-based motion effect to widgets.

A Flutter plugin to apply a gyroscope-based motion effect to widgets.

Motion for Flutter widgets This package adds a new Motion widget that applies a gyroscope-based effect to Flutter widgets. On desktop or when the gyro

Dec 29, 2022

Hero Effect for common words of two Text (Flutter)

Hero Effect for common words of two Text (Flutter)

Hero Effect for common words of text widget (something like magic move in keynote) Features Usage Usage is easily and likes Hero,but obviously the chi

Oct 12, 2022

Bottom navigation bar with sliding clip effect.

Bottom navigation bar with sliding clip effect.

Sliding Clipped Nav Bar Design Credit Toolbar icons animation by Cuberto How to use? API reference barItems → ListBarItem List of bar items that sho

Dec 3, 2022

Animated shimmer - A simple & lightweight widget to display an animated shimmer effect

Animated shimmer - A simple & lightweight widget to display an animated shimmer effect

Animated Shimmer Supports Null Safety A simple & lightweight widget to display a

Apr 27, 2022

Gyroscope-based Parallax Effect

sensor_image_demo A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you starte

Jan 4, 2023

Add a fading effect when the user can scroll.

Add a fading effect when the user can scroll. Demo Quickstart Add the dependency to fading_scroll to your pubspec.yaml file. flutter pub add clickup_f

Dec 14, 2022
Comments
  • nayuta_sensors cant update

    nayuta_sensors cant update

    pub get error: Because example depends on nayuta_sensors any which doesn't exist (could not find package nayuta_sensors at https://pub.flutter-io.cn), version solving failed.

    opened by 865394064 1
Owner
FlutterCandies
Custom Flutter candies (packages) for you to build your Flutter app easily. Enjoy it!
FlutterCandies
Fancy list loading effect or The Shimmer Effect in Flutter

Shimmer Effect in Shimmer Effect is really cool placeholder effect that you can show when you are loading data in the form of a list. To do it in flut

Ronak Punase 31 Oct 18, 2022
The Ken Burns effect is a type of panning and zooming effect used in video production from still imagery.

KenBurns The Ken Burns effect is a type of panning and zooming effect used in video production from still imagery. First add to your dependencies: dep

Favour Olukayode 1 Apr 28, 2022
Let's deliver Flutter app using Fastlane and self-hosted runner.

Flutter CICD - Let's deliver app using Fastlane and Github selfhosted runner About This project shows how to create a minimal configuration for buildi

Codigee 3 Nov 17, 2022
A beautiful 😍 covid-19 app with self - assessment and more.

Aarogya Seva Made with ?? in India ?? Aarogya Seva is an Indian app developed using flutter for tracking live Covid-19 cases. App provides Coronavirus

Shubham Soni 118 Nov 25, 2022
This is a Clone FinkuApp Inspired by This Real App It Self, Finku is a Money Management Tracker Develop by Fintech

?? Finku App This is a Clone FinkuApp Inspired by This Real App It Self, Finku is a Money Management Tracker Develop by Fintech. ?? Installing depende

fizfat 9 Dec 16, 2022
A streaming client for the Komga self-hosted comics/manga/BD server targeting Android/iOS written in Dart/Flutter

Klutter A streaming client for the Komga self-hosted comics/manga/BD server targeting Android/iOS written in Dart/Flutter Background This is a project

Mark Winckle 58 Dec 7, 2022
A self-hosted controller for mobile and macOS built using the Flutter framework.

LunaSea LunaSea is a fully featured, open source self-hosted controller! Focused on giving you a seamless experience between all of your self-hosted m

Comet.Tools 844 Jan 2, 2023
Dart port of FormCoreJS: A minimal pure functional language based on self dependent types.

FormCore.js port to Dart. So far only the parser and typechecker have been ported i.e. the FormCore.js file in the original repo. (Original readme fro

Modestas Valauskas 2 Jan 28, 2022
Immich - Self-hosted Photo backup solution directly from your mobile phone

IMMICH Self-hosted Photo backup solution directly from your mobile phone. Note T

Alex 6.6k Dec 31, 2022
Drop shadow effect for any widget in Flutter

DropShadow Drop shadow effect for any widget in flutter Parameters Widget child; // required double blurRadius; // default: 10.0 double borderRadius;

null 10 Nov 26, 2022