Compose版来啦!仿自如裸眼3D效果
前段时间自如团队实现了App裸眼3D效果,确实让人眼前一亮,昨天Nayuta 大佬使用Flutter也实现了该功能,那Jetpack compose版本怎么能落下。
前人栽树后人乘凉,首先在这里感谢自如大前端团队 和Nayuta ,下文所用的素材也有一部分来自Nayuta ,再次感谢。
思路
从自如团队所提供的思路来看,裸眼3D效果是将整个图片结构分为3层:上层、中层、以及底层。
在手机左右上下旋转时,上层和底层的图片呈相反的方向进行移动,中层则不动,在视觉上给人一种3D的效果。
至于使用Jetpack Compose来实现,主要想法如下:
- 使用Compose 的Canvas对三层图片进行绘制,且使用translate对上层和底层图片进行平移;
- 注册手机陀螺仪传感器的监听,拿到手机旋转时,xyz轴的旋转角度;
- 根据旋转角度计算图片平移的距离,期间做好最大平移距离的控制;
- 得到平移距离后,将距离设置给标记了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效果相关推荐
- Android OpenGL 仿自如 APP 裸眼 3D 效果
概述 之前看到 自如团队 发布的 自如客APP裸眼3D效果的实现 ,非常有趣,不久后,社区内 Android 的开发者们陆续提供了 Flutter. Android 原生 .Android Jetpa ...
- 卷起来了!Android OpenGL仿自如APP裸眼3D效果
/ 今日科技快讯 / 近日,"乘联会"微信公众号发布消息,2021年12月新能源乘用车市场多元化发力,厂商批发销量突破万辆的企业有14家,较前期大幅增多,其中:比亚迪933 ...
- 设计师:裸眼 3D 效果,你们客户端实现很难吗?
自如-黄进 | 作者 承香墨影 | 编辑 https://juejin.cn/post/6989227733410644005 | 原文 Hi,大家好,这里是承香墨影! 说到裸眼 3D 效果,最先想到 ...
- 怎么设置ppt页面的长度和宽度_在PPT中将照片变裸眼3D效果怎样操作?分享技巧,帮你快速实现...
PPT的使用相信大家都不陌生,使用最多的就是制作PPT对工作进行汇报,对新项目进行展开讨论.其实在PPT中还可以设计海报,制作高逼格封面以及将照片变为3D效果等偏设计类的操作.今天将以如何把照片变为3 ...
- 投影仪的裸眼3D效果
裸眼3D是指在看投影仪投出来的画面时,不需要戴3D眼镜就能看到立体效果的技术.裸眼3D投影仪通常使用两个投影仪同时投出左右眼图像,利用人眼视差原理来产生立体效果.这种方式看起来比较自然,但是画面质量通 ...
- 基于android的裸眼3d,午诺裸眼3D原理其实并不复杂
午诺裸眼3D原理其实并不复杂 其实同样是裸眼3D手机,可能其中含有的技术却大不相同.午诺P8采用的是国内领先3D光学厂商康得新提供的柱状光栅技术,屏幕通过特殊处理给左右眼的图像是不一样的,消费者面对手 ...
- 裸眼 3D 是什么效果?
作者:沙因,腾讯 IEG 前端开发工程师 介绍一种裸眼 3D 的实现方式,代码以 web 端为例. 平常我们都是戴着 3D 眼镜才能感受 3D 效果,那裸眼能直接看 3D 么?可以看看下面这个视频: ...
- 户外LED显示屏如何实现裸眼3D显示效果:创造逼真立体体验的新视界
随着科技的不断进步,户外LED显示屏已成为现代广告和娱乐领域中不可或缺的元素.而在这个数字化时代,人们对于视觉体验的要求也越来越高.裸眼3D效果作为一种引人注目的显示技术,为户外LED显示屏注入了全新 ...
- 成都太古里,溢出屏幕的裸眼3d
在成都太古里和春熙路交界处有一块裸眼3D屏,早在十月份的时候就凭借一段酷炫真实的外星飞碟裸眼3d视频登上热搜,刷爆朋友圈,让本就是打卡圣地的太古里再一次上升成为一个网红打卡必经之地. 数字平原有幸参与 ...
- 史帝奇文旅项目篇——穿越式裸眼3D轨道影院
目前国内 A 级景区.文化商业街区.城市商业空间等文旅目的地急需,提质增收促进二消,提供造血功能.以投资小.见效快.精运营.品质化的新业态.新场景成为未来文旅市场的重要商机. "穿越式裸眼3 ...
最新文章
- 300 多行代码搞定微信 8.0 的「炸」「裂」特效!
- Linux静态IP设置
- 上手kubernetes之前,你应该知道这6件事
- setsockopt()函数功能介绍
- Java中的主类概念以及public static void main方法的分析
- 文件html怎么另存为wps,WPS文字中另存为功能详解(wps文字怎么保存到指定文件夹)...
- Qt5中生成和使用静态库
- leetcode 792. Number of Matching Subsequences | 792. 匹配子序列的单词数(Java)
- maven profile实现多环境构建 (单项目多套配置)
- 使用 .NET CLI 构建项目脚手架
- 城市公交网建设问题(信息学奥赛一本通-T1348)
- [转载] C++ 中的浮点代码优化
- UE4之变量、定时器和事件
- mysql 数据库快速入门 数据库的发展
- 网站开发之HTML基础知识及超链接(二)
- 朋友,我真诚的劝你别网贷
- 如果你是我眼中一滴泪,那么我永远不会哭
- IDEA插件-----FindBugs
- 设计模式之禅学习总结
- C语言-对文件的输入输出
热门文章
- MongoDB可视化客户端管理工具之NoSQLbooster4mongo
- 云算法——骑士在棋盘上的概率之公主当不了堂吉诃德
- fiddler 证书错误
- 大型sql文件拆分工具软件
- 英语单词发音中/s/后的/p/,/t/,/k//tr/什么时候读作/b/,/d/,/g/,/dr/?
- 重言式判定------参考了别人的代码。。
- Foxmail是否可以隐藏文件夹?【网易企业邮箱申请】
- Android 客户端无法访问 服务器,无法将Android客户端与本地XMPP服务器连接
- 2-13 monthCalendar日历控件
- html5 拖拽 编辑 插件,超给力 Vue.js 可视化H5拖拽编辑器Quark-H5