前段时间自如团队实现了App裸眼3D效果,确实让人眼前一亮,昨天Nayuta 大佬使用Flutter也实现了该功能,那Jetpack compose版本怎么能落下。

前人栽树后人乘凉,首先在这里感谢自如大前端团队 和Nayuta ,下文所用的素材也有一部分来自Nayuta ,再次感谢。

思路

从自如团队所提供的思路来看,裸眼3D效果是将整个图片结构分为3层:上层、中层、以及底层。
在手机左右上下旋转时,上层和底层的图片呈相反的方向进行移动,中层则不动,在视觉上给人一种3D的效果。

至于使用Jetpack Compose来实现,主要想法如下:

  1. 使用Compose 的Canvas对三层图片进行绘制,且使用translate对上层和底层图片进行平移;
  2. 注册手机陀螺仪传感器的监听,拿到手机旋转时,xyz轴的旋转角度;
  3. 根据旋转角度计算图片平移的距离,期间做好最大平移距离的控制;
  4. 得到平移距离后,将距离设置给标记了mutableStateOf的平移距离变量,使得UI刷新,呈平移效果。

实现

根据上面的思路,我们首先使用compose绘制出静态的三张图片,compose绘制图片的方式有多种,Image、Canvas等,因为考虑到后面图片需要进行移动,这里就选用Canvas进行绘制。


val imageBack = ImageBitmap.imageResource(id = R.drawable.back)
val imageMid = ImageBitmap.imageResource(id = R.drawable.mid)
val imageFore = ImageBitmap.imageResource(id = R.drawable.fore)Canvas(modifier = Modifier.fillMaxSize()) {//底层drawImage(imageBack)//中层drawImage(imageMid)//sdrawImage(imageFore)}

生成静态的效果图如下:

静态图片加载是件简单的事情,那如何让图片动起来?

Compose的Canvas中有一个translate方法,作平移效果用,也就是分别在x和y坐标中通过给定的像素增量对坐标空间进行平移。参数传入x轴上平移的距离以及y轴上平移的距离。这里分别定义为xDistance,yDistance。因为只有上层和底层的图片会进行移动,所以在Canvas中,对上层和底层图片的绘制加上translate,如下:

 translate(-xDistance, -yDistance) {drawImage(imageBack)}drawImage(imageMid)translate(xDistance, yDistance) {drawImage(imageFore)}

传入xDistance,yDistance参数值,这里需要注意的是,上层与底层图片为互为相反移动,所以对上层图片传入的是xDistance的相反值。到这里,图片就会根据xDistance以及yDistance的距离进行平移。

那xDistance和yDistance的值该如何动态改变呢?

Compose其实提供了一个状态mutableStateOf
标记了mutableStateOf的data后,该data就表明是有状态的,如果后续状态发生了改变,那么所有引用这个状态的控件都会重新绘制。也就是说,将xDistance和yDistance设置成该状态,因为Canvas引用了xDistance值,所有当xDistance值发生改变时,图片也就会重新绘制,也就是做平移的效果。

如下:

var xDistance by remember { mutableStateOf(0f) }
var yDistance by remember { mutableStateOf(0f) }

xDistance和yDistance已经动态标记。下面就需要依据手机陀螺仪移动,来动态设置xDistance和yDistance的值。在开始说传感器之前,这里还存在一个问题,当图片进行平移上下或者作用平移时,会存在左右或者上下两侧屏幕露出的情况,这个时候就需要将图片做放大处理,
给图片设置边界,让图片在最大平移距离中移动,防止图片平移露出屏幕背景,将Canvas设置为原来的1.3倍。

Canvas(modifier = Modifier.fillMaxSize().scale(1.3f)) {}

最后的效果也就是如下所示:

手机陀螺仪传感器

通过手机的旋转,图片进行移动的操作归功于传感器,

如图所示,传感器坐标系一共分为x,y,z三轴,当手机左右翻转时,则是围绕Y轴运动,当手机上下翻转时,则是围绕x轴运动,当手机平放在桌面,左右画圆时,则是围绕z轴运动。

当手机旋转时,传感器则会通知我们三个方向的移动角速度,也就根据这移动角度来确定图片的平移距离。

首先我们先看看传感器该如何监听?Android其实已经为我们封装好了API,SensorManager,直接按照说明创建就好。

    val context = LocalContext.currentval sensorManager: SensorManager? = getSystemService(context, SensorManager::class.java)val sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

通过getSystemService获取到SensorManager后,设置sensor的种类为TYPE_GYROSCOPE,也就是陀螺仪传感器。并且监听xyz三个方向旋转角速度。

sensorManager?.registerListener(object : SensorEventListener {override fun onSensorChanged(event: SensorEvent?) {//Y轴角速度speedY = event?.values?.get(1)!!//X轴角速度speedX = event?.values?.get(0)!!//Z轴角速度speedZ = event?.values?.get(2)!!}override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
}

通过SensorEventListener监听到手机三个方向的角速度,因为陀螺仪读出的是角速度,大家都知道,角速度乘以时间,就是转过的角度,直接计算旋转的角度值。

 // 将手机在各个轴上的旋转角度相加angularX += (event.values[0] * dT).toLong()angularY += (event.values[1] * dT).toLong()angularZ += (event.values[2] * dT).toLong()//设置x轴y轴最大边界值,if (angularY > mMaxAnular) {angularY = mMaxAnular.toFloat()} else if (angularY < -mMaxAnular) {angularY = -mMaxAnular.toFloat()}if (angularX > mMaxAnular) {angularX = mMaxAnular.toFloat()} else if (angularX < -mMaxAnular) {angularX = -mMaxAnular.toFloat()}

角度计算完成后,因为图片移动是需要移动距离的,那接下来就需要知道图片的平移距离。其实在上面就提出为图片设置了最大平移边界,这里也设置了最大旋转角度,那么就可以依据角度比例来到推出平移距离。

依据公式旋转角度/最大角度 = 平移距离/最大平移距离 反推出 平移距离= 旋转角度/最大角度*最大平移距离

                 val xRadio: Float = (angularY / mMaxAnular).toFloat()val yRadio: Float = (angularX / mMaxAnular).toFloat()xDistance = xRadio * maxOffsetyDistance = yRadio * maxOffset

图片距离计算完成,基本上随手机移动,图片会呈平移效果,但是发现还有一个问题,onSensorChanged的回调刷新很快,当围绕Y轴左右运动时,图片也会上下平移,这就导致图片会不规则跳动,绕Y轴左右运动其实只需要左右平移即可,同样的,围绕x轴运动,图片只需要上下移动即可。这里针对x,y轴运动,设置了旋转条件控制。

  x = Math.abs(event.values[0])y = Math.abs(event.values[1])z = Math.abs(event.values[2])if (x > y + z) {xDistance = 0fyDistance = yRadio * maxOffset} else if (y > x + z) {xDistance = xRadio * maxOffsetyDistance = 0f}

好了,功能完成,我们来看看最后的效果:

最后

市面上的App的设计基本上是千篇一律,一个有意思的idea总是会让人多看一眼,再次感谢自如团队提供了这个创意。对了,今天在蚂蚁森林收能量时,发现树木也有点此效果的味道,你不妨去瞅一眼。

参考资料:

自如客APP裸眼3D效果的实现

拿去吧你!Flutter 仿自如 App 裸眼 3D 效果| 8月更文挑战

推荐阅读:

玩会儿Compose,原神主题列表

Compose版来啦!仿自如裸眼3D效果相关推荐

  1. Android OpenGL 仿自如 APP 裸眼 3D 效果

    概述 之前看到 自如团队 发布的 自如客APP裸眼3D效果的实现 ,非常有趣,不久后,社区内 Android 的开发者们陆续提供了 Flutter. Android 原生 .Android Jetpa ...

  2. 卷起来了!Android OpenGL仿自如APP裸眼3D效果

    /   今日科技快讯   / 近日,"乘联会"微信公众号发布消息,2021年12月新能源乘用车市场多元化发力,厂商批发销量突破万辆的企业有14家,较前期大幅增多,其中:比亚迪933 ...

  3. 设计师:裸眼 3D 效果,你们客户端实现很难吗?

    自如-黄进 | 作者 承香墨影 | 编辑 https://juejin.cn/post/6989227733410644005 | 原文 Hi,大家好,这里是承香墨影! 说到裸眼 3D 效果,最先想到 ...

  4. 怎么设置ppt页面的长度和宽度_在PPT中将照片变裸眼3D效果怎样操作?分享技巧,帮你快速实现...

    PPT的使用相信大家都不陌生,使用最多的就是制作PPT对工作进行汇报,对新项目进行展开讨论.其实在PPT中还可以设计海报,制作高逼格封面以及将照片变为3D效果等偏设计类的操作.今天将以如何把照片变为3 ...

  5. 投影仪的裸眼3D效果

    裸眼3D是指在看投影仪投出来的画面时,不需要戴3D眼镜就能看到立体效果的技术.裸眼3D投影仪通常使用两个投影仪同时投出左右眼图像,利用人眼视差原理来产生立体效果.这种方式看起来比较自然,但是画面质量通 ...

  6. 基于android的裸眼3d,午诺裸眼3D原理其实并不复杂

    午诺裸眼3D原理其实并不复杂 其实同样是裸眼3D手机,可能其中含有的技术却大不相同.午诺P8采用的是国内领先3D光学厂商康得新提供的柱状光栅技术,屏幕通过特殊处理给左右眼的图像是不一样的,消费者面对手 ...

  7. 裸眼 3D 是什么效果?

    作者:沙因,腾讯 IEG 前端开发工程师 介绍一种裸眼 3D 的实现方式,代码以 web 端为例. 平常我们都是戴着 3D 眼镜才能感受 3D 效果,那裸眼能直接看 3D 么?可以看看下面这个视频: ...

  8. 户外LED显示屏如何实现裸眼3D显示效果:创造逼真立体体验的新视界

    随着科技的不断进步,户外LED显示屏已成为现代广告和娱乐领域中不可或缺的元素.而在这个数字化时代,人们对于视觉体验的要求也越来越高.裸眼3D效果作为一种引人注目的显示技术,为户外LED显示屏注入了全新 ...

  9. 成都太古里,溢出屏幕的裸眼3d

    在成都太古里和春熙路交界处有一块裸眼3D屏,早在十月份的时候就凭借一段酷炫真实的外星飞碟裸眼3d视频登上热搜,刷爆朋友圈,让本就是打卡圣地的太古里再一次上升成为一个网红打卡必经之地. 数字平原有幸参与 ...

  10. 史帝奇文旅项目篇——穿越式裸眼3D轨道影院

    目前国内 A 级景区.文化商业街区.城市商业空间等文旅目的地急需,提质增收促进二消,提供造血功能.以投资小.见效快.精运营.品质化的新业态.新场景成为未来文旅市场的重要商机. "穿越式裸眼3 ...

最新文章

  1. 300 多行代码搞定微信 8.0 的「炸」「裂」特效!
  2. Linux静态IP设置
  3. 上手kubernetes之前,你应该知道这6件事
  4. setsockopt()函数功能介绍
  5. Java中的主类概念以及public static void main方法的分析
  6. 文件html怎么另存为wps,WPS文字中另存为功能详解(wps文字怎么保存到指定文件夹)...
  7. Qt5中生成和使用静态库
  8. leetcode 792. Number of Matching Subsequences | 792. 匹配子序列的单词数(Java)
  9. maven profile实现多环境构建 (单项目多套配置)
  10. 使用 .NET CLI 构建项目脚手架
  11. 城市公交网建设问题(信息学奥赛一本通-T1348)
  12. [转载] C++ 中的浮点代码优化
  13. UE4之变量、定时器和事件
  14. mysql 数据库快速入门 数据库的发展
  15. 网站开发之HTML基础知识及超链接(二)
  16. 朋友,我真诚的劝你别网贷
  17. 如果你是我眼中一滴泪,那么我永远不会哭
  18. IDEA插件-----FindBugs
  19. 设计模式之禅学习总结
  20. C语言-对文件的输入输出

热门文章

  1. MongoDB可视化客户端管理工具之NoSQLbooster4mongo
  2. 云算法——骑士在棋盘上的概率之公主当不了堂吉诃德
  3. fiddler 证书错误
  4. 大型sql文件拆分工具软件
  5. 英语单词发音中/s/后的/p/,/t/,/k//tr/什么时候读作/b/,/d/,/g/,/dr/?
  6. 重言式判定------参考了别人的代码。。
  7. Foxmail是否可以隐藏文件夹?【网易企业邮箱申请】
  8. Android 客户端无法访问 服务器,无法将Android客户端与本地XMPP服务器连接
  9. 2-13 monthCalendar日历控件
  10. html5 拖拽 编辑 插件,超给力 Vue.js 可视化H5拖拽编辑器Quark-H5