重溫今日頭條螢幕適配方案

語言: CN / TW / HK

theme: cyanosis highlight: github


前言

有這麼一個需求:通過一個PC的佈局編輯器配置佈局,傳送到Android平板上展示。這個編輯器我們這裡叫它“拖拉拽”系統。Android平板需要根據“拖拉拽”傳送過來的控制元件資訊,等比例的渲染控制元件,並根據附加的配置做一些事件的響應。 image.png

可以簡單理解為低程式碼的兒童版啦,但本文的主題是等比例怎樣實現的問題。提到等比例,筆者當時第一時間想到的是今日頭條螢幕適配方案。所以本文就著重通過複習該方案,來記錄一下需求的實現過程吧。

基礎回顧

這裡貼兩篇文章回顧一下關於解析度、DPI/PPI等基礎知識:

android解析度 尺寸 dpi換算

DPI和PPI

還有搞Android螢幕適配都需要看的幾條公式:

px = density * dp; density = dpi / 160; px = dp * (dpi / 160);

今日頭條螢幕適配方案

先貼一下官方的推文:

一種極低成本的Android螢幕適配方式

該方案是一個百分比螢幕適配方案,區別於Google給出的一些根據解析度的適配。這一類方案的優點在於可以在不同裝置螢幕上呈現與設計圖幾乎一樣的效果,而無需特別關注在開發中設定的某個控制元件的dp值。需要注意的是這裡只是幾乎而已。。。

如果您是沒有了解過的話,可能會覺得這種方案好像很強大。但其實細想一下,這一類方案只是在開發成本和使用者體驗上的一種折中方案啦。亦或者說是簡單粗暴而又帶一點不負責任的適配方法,因為從使用者使用的角度出發,如果自己使用的是一臺大螢幕的手機,還是希望自己在一屏內的內容足夠多且富有層次感,而不是還是和自己前兩年的那臺小螢幕一樣嘛。只能說Android的碎片化,令這一切的開發成本大大提高了。

簡單說了一下筆者的理解,方案的優缺點就不展開了,已經有很多文章了。這裡可以參考:

騷年你的螢幕適配方式該升級了!-今日頭條適配方案

回到方案本身,方案的實現其實就是利用了px = density * dp;這條公式。核心思想是:通過動態修改density,來改變您佈局當中按照設計圖設定的dp值計算出來的px

density的計算還是使用px = density * dp;,譬如優先對螢幕寬度適配,可以假設螢幕寬度為1080,設計圖以寬度為360dp為基準。那麼這裡就能求出當裝置寬度為1080px,360dp的density是多少,denstiy = px / dp,後續就可以通過計算出來的density自動換算佈局。今日頭條的做法是通過修改DisplayMetrics,來達到解析的xml滿足效果的。

ps:需要注意的是,這裡是優先對螢幕寬度適配的。因為理想狀態下,裝置寬高比和設計圖寬高比應該是一致的。實際情況是裝置的寬高比千奇百怪,如果嚴格按照寬寬比和高高比計算的話就會產生變形問題。可參考: 為什麼說 AndroidAutoLayout 的設計有問題?

ps:這種計算方法是將density重新定義的,它繞開了dpi。

需求實現

為什麼筆者在開頭會說第一時間想到的是今日頭條適配方案呢?因為需求上說的等比例其實就是一個百分比適配的問題嘛。區別在於筆者的目標不是計算一個density出來,而是需要計算出一個比例係數(其實也是那麼回事啦)。

回頭看需求本身,“拖拉拽”會以一塊1920 * 1080的畫布為基礎,在此基礎上進行控制元件的拖拉拽。所以這裡就可以將1920類比成設計圖的寬度,也就是px = density * dp;中的dp,那麼px就是螢幕寬度了。所以會有公式:

// denstiy = px / dp 比例係數d = 螢幕寬度 / 畫布寬度(1920)

舉例說明

筆者用一臺華為Matepad 11進行測試

尺寸:10.95英寸

解析度:2560 x 1600,275每英寸畫素

計算比例係數d 比例係數d = 2560 / 1920 = 1.3333333 PC端有一圖片控制元件

json // x, y 控制元件的起始座標;w, h 控制元件的寬高。 { "x": 100, "y": 100, "w": 100, "h": 100 } 轉換成真實顯示 ps:這裡筆者暫時用AbsoluteLayout.LayoutParams演示 kotlin val layoutParams = AbsoluteLayout.LayoutParams( (1.3333333 * it.w).toInt(), (1.3333333 * it.h).toInt(), (1.3333333 * it.x).toInt(), (1.3333333 * it.y).toInt()) 這樣就能得到幾乎和PC端相同的效果了,大概草圖就是開頭貼出的效果: image.png

螢幕寬高比問題

前面講今日頭條適配方案時也有提到過,該方案是優先適配寬度的。這裡舉個例子就知道發生什麼問題了: - PC端的畫布為1920 * 1080,比例是16:9 - 筆者的Matepad 11螢幕寬高為2560 * 1600,顯然不是16:9

這樣顯示出來就會變成下圖這樣了,紅色虛線框的部分就是高度多出來的部分。因為是優先按寬度適配的,所以一般寬度是等比的。 image.png

解決的方案也只能是將父控制元件的寬高設定成16:9。當然了,這個就不是程式設計師能決定的事情了哈哈哈。

最後

本文通過一個小需求,重新複習一下今日頭條螢幕適配方案,也簡單重溫了有關Android的螢幕適配。在開發時也是總被這些概念繞暈,所以筆者特意寫一篇文章加以記錄。