自如客APP裸眼3D效果的實現
背景
移動端界面設計如此火熱的今天,各類大廠的設計規範和設計語言已經非常的成熟,我們想做一些在這套成熟的設計規範之外的嘗試和創新,所以有別於傳統的banner交互形式成為了我們的發力點。
設計理念
由於app版面空間有限,除了功能導向、閲讀習慣和設計美觀外,自如想在既定的框下,做一下不同的設計嘗試,哪怕這種嘗試只能提升用户1%的觀感。可能租了幾年自如的房子,用了幾年自如客app,你可能也不會注意到一些小的細節。但如果哪天,作為用户的你突然發現了這個隱藏的“彩蛋”,看到了自如在這些小細節上的用心,我相信那天你將會對自如這個品牌有更深層次的認識和理解。
裸眼3D技術一般都是應用在裸眼3D大屏、全息投影等等比較常見的場景中,在APP的banner上應用,的確也是一次全新的嘗試。我們通過藉助移動設備上的傳感器、以及自身的屏顯清晰度、畫面呈現,將2D影像轉化為景深效果,以呈現出不用"3D"眼鏡就可看到的3D效果。
實現方式
以下以Android為例,介紹一下該效果的實現方式。
分層
自如客app的banner其實一直在創新當中,有專門注意過的同學可能知道,在裸眼3D效果之前,自如客app其實就已經實現了分層,當時為了實現更加自然和精緻的切換效果:在每個banner滑入滑出的時候,底部其實會在原地進行漸顯漸隱,內容會跟隨手勢滑入滑出。此次為了實現3D效果,我們在以前分層的基礎上加了一層中景,將原有的前景拆分為前景和中景。
上圖的sl_bg為背景,pv_middle為中景,sl為前景
由於切換的交互,實際上banner使用了兩個viewpager進行了聯動。背景在最底層的viewpager裏面,中景和前景在另外一個viewpager裏。
跟手位移
打開自如客app後,用户操作設備可以明顯感受到畫面的錯位移動,造成視覺上的景深效果。這種錯位移動其實就是藉助設備本身的傳感器來實現的,具體實現方式是我們讓中景始終保持不動,同時從設備傳感器獲取當前設備對應的傾斜角,根據傾斜角計算出背景和前景的移動距離,然後執行背景和前景移動的動作。如下圖所示:
為了使用的方便,我們封裝了一個SensorLayout,專門用於根據設備的傾斜角執行內容的位移; SensorLayout內部的主要實現:
註冊對應的傳感器
```java mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE); // 重力傳感器 mAcceleSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 地磁場傳感器 mMagneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mSensorManager.registerListener(this, mAcceleSensor, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mMagneticSensor, SensorManager.SENSOR_DELAY_GAME); ```
計算偏轉角度
```java if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { mAcceleValues = event.values; } if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { mMageneticValues = event.values; }
float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, mAcceleValues, mMageneticValues); SensorManager.getOrientation(R, values); // x軸的偏轉角度 values[1] = (float) Math.toDegrees(values[1]); // y軸的偏轉角度 values[2] = (float) Math.toDegrees(values[2]);
``` 通過重力傳感器和地磁場傳感器,獲取設備的偏轉角度
根據偏轉角度執行滑動
java
if (mDegreeY <= 0 && mDegreeY > mDegreeYMin) {
hasChangeX = true;
scrollX = (int) (mDegreeY / Math.abs(mDegreeYMin) * mXMoveDistance*mDirection);
} else if (mDegreeY > 0 && mDegreeY < mDegreeYMax) {
hasChangeX = true;
scrollX = (int) (mDegreeY / Math.abs(mDegreeYMax) * mXMoveDistance*mDirection);
}
if (mDegreeX <= 0 && mDegreeX > mDegreeXMin) {
hasChangeY = true;
scrollY = (int) (mDegreeX / Math.abs(mDegreeXMin) * mYMoveDistance*mDirection);
} else if (mDegreeX > 0 && mDegreeX < mDegreeXMax) {
hasChangeY = true;
scrollY = (int) (mDegreeX / Math.abs(mDegreeXMax) * mYMoveDistance*mDirection);
}
smoothScrollTo(hasChangeX ? scrollX : mScroller.getFinalX(), hasChangeY ? scrollY : mScroller.getFinalY());
mDegreeX即為第二部中獲取的偏轉角度,mDegreeXMin和mDegreeXMax為X軸可發生偏轉位移的角度最大值和最小值,mYMoveDistance即為Y軸上的最大偏移距離(圍繞X軸發生旋轉,視圖會沿Y軸上發生位移);Y軸上的偏轉同理;就算好X軸和Y軸的偏移距離後,使用scroller進行滑動;
實現總結
讀到這裏,相信大家已經基本瞭解了這套banner的實現方案。Android端在佈局上進行了分層,中景位置不變,藉助重力傳感器和地磁場傳感器獲取偏轉角度,根據角度使背景和前景進行錯位移動。iOS端的實現原理也基本一致,不再贅述。
本文作者:自如大前端研發中心-黃進
招聘信息
自如大前端研發中心招募新同學!
FE/IOS/Android工程師看過來
公司福利有: - 全額五險一金,並額外購買商業保險 - 免費健身房+年度體檢 - 公司附近租房9折優惠 - 每年2次晉升機會 辦公地點:北京酒仙橋普天實業科技園 歡迎對技術有執着熱愛的你加入我們!簡歷請投遞 [email protected]!