小程式 Canvas繪圖不同尺寸裝置 UI相容的兩個解決方案
最近做的一個需求,遇到一個問題,小程式繪圖目前只支援 px
單位,設計圖一般是以 iphone6
為基準設計,如果嚴格 iphone6
的尺寸進行程式碼編寫,放在其他尺寸的裝置上,肯定是不行的,所以需要按照裝置進行等比例相容,這裡給出兩個解決方案
先假設一個需求,下面是最終實現的效果(以 iphone6
為基準),下面就以此為目標進行展開

整個頁面被 canvas
元件覆蓋(在 iphone6
下寬高為 375x603
),中間偏藍色的是一張圖片,圖片上有一行字 flexible canvas
類 rem
等比例縮放單位的解決方案,也就是以一個尺寸為基準,例如 iphone 6
,然後其他裝置按照這個標準,在保證寬度鋪滿裝置的前提下,進行等比例縮放
繪製的程式碼很簡單:
const ctx = wx.createCanvasContext('shareCard') ctx.drawImage('../58a.png', this.remSize(85), this.remSize(100), this.remSize(205), this.remSize(250)) ctx.setFontSize(this.remSize(16)) ctx.setFillStyle('yellowgreen') ctx.fillText('flexible canvas', this.remSize(100), this.remSize(130)) ctx.draw() 複製程式碼
其中, remSize
這個方法就是用於等比例縮放尺寸
remSize (num) { return num * scale } 複製程式碼
其中, scale
就是當前裝置與設計基準裝置 iphone6
的寬度比例
scale = wx.getSystemInfoSync().windowWidth / 375 複製程式碼
當前是以鋪滿裝置寬度為目標,所以高度不關心,即 以寬度為參考,高度 auto
以上,就基本實現需求,做法很簡單,這是通常一貫的解決方案 由於示例的需求比較簡單,所以看著沒多大問題,很完美,但是如果實際需求,比較複雜的那種,就有點不太美好了 哪裡不美好呢?就是換算尺寸的時候,每個尺寸都要呼叫一遍 remSize
方法,稍微複雜點需求可能就有幾十個需要換算的尺寸了,那就要寫幾十遍的 remSize
,當然,寫是可以寫的,只是總感覺哪裡不太對勁
圖片代替
這個方法不需要頻繁的尺寸換算,最後統一整體換算即可,原理也很簡單
- 按照
iphone6
尺寸進行繪製
首先,無論當前裝置的尺寸是什麼,都不用管,先認為當前裝置就是 iphone6
,然後建立 canvas
,在上面進行繪圖,只不過,不能讓使用者看到這個 canvas
,因為當前裝置並不一定是 iphone6
,而你直接就認定是 iphone6
,並以 iphone6
的尺寸進行繪製,繪製出來的效果肯定跟設計的效果不一樣,所以不能讓使用者看到,可以使用 ccover-view
元件覆蓋掉 canvas
元件
Note: 如果想要通過給 canvas
設定例如 opacity: 0
, visibility: hidden
等樣式進行隱藏,根據實測,在大部分的手機上其實無法生效,也就是依舊能看到, display: none;
則是徹底將 canvas
從文件流中(如果也算是文件流的話)刪掉,無法進行繪製,所以比較好的做法就是用一個 cover-view
進行覆蓋
- 將繪製好的
canvas
輸出為 圖片
canvas
繪製好後,將其繪製成圖片儲存在本地臨時儲存中,可以拿到這個圖片在本地的臨時路徑,然後將這張圖片放到頁面上,並給這張圖片設定尺寸樣式,圖片的寬度等於裝置的寬度,高度跟隨寬度進行等比例縮放,最終讓使用者看到的就是這張圖片,因為進行了等比例縮放,所以視覺效果就是和設計圖上是一樣的
這裡也有幾個點需要注意下
-
ctx.draw
是非同步操作
一直以為這個方法是同步方法,所以呼叫完此方法後立即輸出圖片,就出現了有時候圖片錯誤的情況,後來才發現這個是非同步操作,這就是看文件不仔細的後果
ctx.draw(false, () => { // 儲存為本地臨時檔案 this.saveImageToLocal() }) 複製程式碼
- 繪製
canvas
階段,要允許頁面橫向溢位
由於一開始繪製 canvas
是按照 iphone6
的標準進行的,所以在有些寬度小於 iphone6
的裝置上, canvas
的寬度是可能會比裝置的寬度要大的(如果你繪製的是整屏 canvas
),但是小程式頁面的根元素 page
,預設設定了 overflow-x: hiddne;
,導致繪製不完整,所以需要覆蓋這個樣式:
page { overflow-x: scroll; } 複製程式碼
- 繪製完畢後,避免頁面橫向溢位
當上一步繪製完成 canvas
後,併成功將圖片繪製到頁面上時,如果當前裝置的寬度小於 iphone 6
,又由於前面給 page
元素設定了 overflow-x: scroll
,所以此時 canvas
元素肯定會撐大頁面,讓頁面上出現一個橫向的滾動條,而使用者看到的圖片寬度是和裝置寬度相同,不應該出現這種情況
解決方法,一種是直接使用 wx-if
這種條件語句刪掉 canvas
元素,但是在低版本的基礎庫上,可能會報 e.canvasId is undefined
的錯誤(雖然根據實測來看,似乎並不影響正常功能) 第二種就是減少 canvas
的尺寸,反正已經繪製好圖片了,後面也用不到它了,而且使用者也看不到,那就可以隨意減小尺寸,我的做法是乾脆無論寬高通通設為 0
,免得又出現什麼 bug
// 避免在尺寸小的裝置上溢位 this.setData({ canvasWidth: 0, canvasHeight: 0 }) 複製程式碼
以上,兩種方法都可以選擇,各有利弊,第一種要寫很多 rem
轉換,第二種需要做的操作又比較多,各有利弊,根據真實需求進行抉擇即可。
本文可執行示例程式碼已經放到 github 上了,有興趣的可以看下,註釋算是很詳細了,喜歡的話順手 star
哦~