摺疊畫面為什麼能「融化」過去:iPhone Duo 開屏動畫的實作原理
一篇掘金長文拆講 iPhone Duo 開屏動畫的 WebGL 實作原理,從 setAngle 到著色器投影,說明「畫面融化」在技術上如何被做出來。
2026 年 9 月 24 日,掘金上一篇技術長文引起討論,作者「我的刀盾」以可執行的 WebGL 示範,重現了 iPhone Duo 發表會上那段開屏動畫的核心效果。這篇文章的價值不在重現得多像,而在它把蘋果刻意藏起來的運作機制,用幾百行程式碼講清楚了。
先說效果本身。iPhone Duo 展開或折疊時,外屏畫面會逐漸模糊,像透過一扇毛玻璃窗慢慢消融進內屏,兩塊螢幕在視覺上被接成一個連續平面。多數摺疊機在內外屏切換時會有一次生硬的跳屏,蘋果消掉的就是那一下跳動。這與我們在蘋果秋季發表會分析裡提到的方向一致:摺疊機的體驗差距,往往不在硬體規格表上。
角度怎麼變成畫面
整個機制可以用一條資料流講完。
使用者拖滑塊或播放動畫,程式呼叫 setAngle(angle°)。這個函式做三件事:把角度換算成 GPU 用的弧度值寫進 bend.value、在外屏完全展開時把外屏材質乘以零關掉亮度、最後回呼給 UI 層同步滑塊顯示。關鍵在於,setAngle 本身不畫任何東西,它只改狀態。
真正出畫面的是每幀動畫循環末尾的 render。著色器分成兩層:頂點著色器負責機身隨角度變形,片元著色器負責把壁紙投影到彎曲的螢幕面上,再依角度做模糊與壓暗。用日常比喻,就像調一臺可變角度的檯燈:轉旋鈕只是改設定,燈光何時亮、怎麼亮,是電路每瞬間根據目前旋鈕位置算出來的。
角度換算有個容易搞混的地方。介面用「展開角度」,180 度全開、0 度合上;GPU 用的是「折疊角」,展開為 0、合上為 π,方向剛好相反。公式是 bend.value = ((180 - angle) / 180) × π。另外 bend 這個物件在首次編譯著色器時就已綁進 uniform,之後調角度只改 value,不會重跑編譯,這是讓動畫流暢的小細節。
一秒六十次的時間管理
動畫循環裡有三種狀態。播放中時,以 8.6 秒為一個週期,分段走完「展開停留、餘弦曲線合上、合上停留、餘弦曲線打開」,每幀呼叫 setAngle。有過渡任務時,用 1.4 秒的 smoothstep 插值滑到目標角。都沒有時,角度保持原樣,等使用者拖滑塊。
一個務實的處理:每幀的時間增量 delta 被上限鉗制在 0.05 秒,避免切到別的分頁再回來時,一瞬間累積的時間差讓畫面猛跳一格。這類細節平常看不到,卻決定了示範看起來是「順」還是「卡」。
模糊不是加特效,是算出來的
讓畫面「融化」的關鍵在片元著色器。它把彎折中的螢幕面投影成 UV 座標去取樣壁紙,再根據折疊程度套用模糊與壓暗。折得越深,取樣越糊、越暗,內屏與外屏的影像就在這條連續曲線上接起來,中間沒有切換點。
文章還標定了固定的視點位置與內外屏 UI 矩形,讓投影在展開態下對得準。這套做法對做前端互動的人有直接參考價值:任何需要「兩個介面連續過渡」的場景,例如雙欄裝置的拖放互動,都可以借用同一套「狀態與繪製分離」的思路,這在iPhone Duo 拖放機制分析裡也是同一個原則。
對一般讀者,這篇文章的意義在於辨識力。下次看到行銷話術說某摺疊機「無縫切換」,可以問一個具體問題:切換時畫面是跳一下,還是有一段連續的模糊過渡。前者只是兩次全螢幕重繪,後者才需要在圖形層真正處理角度、投影與取樣。差別看不看得出來,看過蘋果這段動畫的人多半已經有答案。
主題