有時覺得寫 layout 就是一個跟格式塔心理對抗的過程

zonble
Sep 11, 2021

最近在工作中累積了一些小小的心得。根據格式塔心理學,人類的大腦往往會將眼前所看到的事物看待成一個整體,並且形塑了對於世界的認知;可是呢,一個 App 工程師在撰寫跟 UI Layout 有關的程式碼的時候,就得小心是否被這種心理所迷惑了。

這麼說吧,當你拿到一份來自 Sketch 或是 Figma 的設計稿,打開編輯器或是 IDE,開始要撰寫程式碼的時候,你要注意的不只是畫面當中有些什麼,也需要注意畫面中那些空白的部份。很多時候,你以為不屬於一個整體的,其實應該要寫成一個整體;至於一些看起來像是個整體的,其實又應該寫成分開的元件。

最近在工作中寫了一個 app,裡頭的畫面像這樣。

我們來看一下下方這一塊的 UI。

看起來不是整體的,可能反而是個整體

如果我們把畫面中的每個元素都各自看待成一個整體,那麼我們直覺的想法,就是把畫面分成三塊:把左邊的車輛與切換模式按鈕、中間的起點終點圖示、以及最右邊起點與終點名稱,分成三個東西。

那麼,問題來了:中間起點與終點的圖示,怎麼與起點以及終點的名稱對齊,地名的長度是會變動的,在長度過長的時候,還有可能會折行?如果寫成兩塊,還要處理兩個元件內部的元件的相互關係,會變得難以處理。

如果是使用 iOS 上面 Storyboard 或是 Auto Layout 這類的排版方式,我們可以用 constraints 來處理,而我們可能會寫出一堆的 constraints。我們可能會把起點與終點的兩行文字,當成是一個元件,兩個文字元件要有固定間隔(第 1 個 constraint),然後圖示要保持與文字之間一定的寬度,並且對齊兩個文字區塊的上方(再加上 4 個 constraint),然後兩個圖示之間的那一串連接用的小點,中心點位置要對齊這兩個圖示,上方與下方分別要與上下兩個圖示保持一定距離(再加 3 個 constraint),然後這一整個區塊也要對齊底下的 view 的整體位置,所以算一算,至少要寫 9 個 constraint。在 constraint 多到一定程度之後,無論是用視覺化工具,或是用程式碼編輯,其實也都沒有多友善。

如果是以表格方式呈現 UI,像 Swift UI 使用 HStack、VStack,或是 Flutter 使用 Row 與 Column 排版,要怎麼製作這樣的 UI 呢?如果我們只看畫面中有內容的部份,就很有可能卡在那邊,一行 code 都寫不出來,因為整個畫面看起來是不規則的,而找不到該組合出怎樣的表格。

這個時候,我們可以嘗試把所有的空白也都畫上一個外框。我們只看所有的外框中,有哪些可以組合成完整的形狀,忽略「兩個圖示之間有條線要跨越一個空白連接起來」這種心理認知。

我們就很容易可以發掘,只要我們把兩段文字當中的空白,直接算到上半部的整體中,就很容易變成方正的表格形狀,我們也馬上知道應該用哪些元件組合了。

用某種 pseudo code 描述這塊 UI 的方式大概像是:

<Row>
<Column><Icon/><Expanded><Icon/></Expanded></Column>
<Column><Text/><Text/><SizedBox/></Column>
</Row>

<Row>
<Column><Icon/></Column>
<Column><Text/><Text/></Column>
</Row>

看起來是整體的反而不見得是整體

然後我們看一下上面這塊。

我們很有可能會把整塊的指針以及上面的數值部分,當成一整個整體,一方面因為兩個元件的位置相鄰,而且在數值不同的時候,這兩個元件也會一起移動。

可是,如果我們考慮邊界狀況,就是數值是最大值或是最小值的時候,就會發現,如果我們這麼寫,那麼指針就會一整個超過版面邊界。

想要不超過邊界,比較合理的排版方式,就是在邊界狀況時,文字應該要往內縮

要達到這種效果,在 Flutter 裡頭可以使用 Align,被 Align 包起來的元件,會往指定的位置偏移(正中央是 0,x 軸從左到右是 -1 到 1,y 軸從上而下是 -1 到 1),但是不會超過版面的邊界。所以,這樣乍看之下是一個整體的東西,我們其實應該把它拆開來,變成兩個 Align。

用外框表達的話,大概像這樣:

--

--