商城系統(tǒng) 注冊(cè)

小程序 Canvas繪圖不同尺寸設(shè)備UI兼容的兩個(gè)解決方案

2020-09-27|HiShop
導(dǎo)讀:最近做的一個(gè)需求,遇到一個(gè)問(wèn)題, 小程序 繪圖目前只支持 px 單位,設(shè)計(jì)圖一般是以 iphone6 為基準(zhǔn)設(shè)計(jì),如果嚴(yán)格 iphone6 的尺寸進(jìn)行代碼編寫,放在其他尺寸的設(shè)備上,肯定是不行的,那么怎...

最近做的一個(gè)需求,遇到一個(gè)問(wèn)題,小程序繪圖目前只支持 px單位,設(shè)計(jì)圖一般是以 iphone6為基準(zhǔn)設(shè)計(jì),如果嚴(yán)格 iphone6的尺寸進(jìn)行代碼編寫,放在其他尺寸的設(shè)備上,肯定是不行的,所以需要按照設(shè)備進(jìn)行等比例兼容,這里給出兩個(gè)解決方案

類 rem

等比例縮放單位的解決方案,也就是以一個(gè)尺寸為基準(zhǔn),例如 iphone 6,然后其他設(shè)備按照這個(gè)標(biāo)準(zhǔn),在保證寬度鋪滿設(shè)備的前提下,進(jìn)行等比例縮放

繪制的代碼很簡(jiǎn)單:

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()
復(fù)制代碼

其中,remSize 這個(gè)方法就是用于等比例縮放尺寸

remSize (num) {
  return num * scale
}
復(fù)制代碼

小程序 Canvas繪圖不同尺寸設(shè)備UI兼容的兩個(gè)解決方案

其中,scale就是當(dāng)前設(shè)備與設(shè)計(jì)基準(zhǔn)設(shè)備 iphone6的寬度比例

scale = wx.getSystemInfoSync().windowWidth / 375
復(fù)制代碼

當(dāng)前是以鋪滿設(shè)備寬度為目標(biāo),所以高度不關(guān)心,即 以寬度為參考,高度 auto

以上,就基本實(shí)現(xiàn)需求,做法很簡(jiǎn)單,這是通常一貫的解決方案 由于示例的需求比較簡(jiǎn)單,所以看著沒(méi)多大問(wèn)題,很完美,但是如果實(shí)際需求,比較復(fù)雜的那種,就有點(diǎn)不太美好了 哪里不美好呢?就是換算尺寸的時(shí)候,每個(gè)尺寸都要調(diào)用一遍 remSize方法,稍微復(fù)雜點(diǎn)需求可能就有幾十個(gè)需要換算的尺寸了,那就要寫幾十遍的 remSize,當(dāng)然,寫是可以寫的,只是總感覺(jué)哪里不太對(duì)勁

圖片代替

這個(gè)方法不需要頻繁的尺寸換算,最后統(tǒng)一整體換算即可,原理也很簡(jiǎn)單

  • 按照 iphone6尺寸進(jìn)行繪制

首先,無(wú)論當(dāng)前設(shè)備的尺寸是什么,都不用管,先認(rèn)為當(dāng)前設(shè)備就是 iphone6,然后創(chuàng)建 canvas,在上面進(jìn)行繪圖,只不過(guò),不能讓用戶看到這個(gè) canvas,因?yàn)楫?dāng)前設(shè)備并不一定是 iphone6,而你直接就認(rèn)定是 iphone6,并以 iphone6的尺寸進(jìn)行繪制,繪制出來(lái)的效果肯定跟設(shè)計(jì)的效果不一樣,所以不能讓用戶看到,可以使用 ccover-view組件覆蓋掉 canvas組件

Note: 如果想要通過(guò)給 canvas設(shè)置例如 opacity: 0, visibility: hidden等樣式進(jìn)行隱藏,根據(jù)實(shí)測(cè),在大部分的手機(jī)上其實(shí)無(wú)法生效,也就是依舊能看到,display: none;則是徹底將 canvas從文檔流中(如果也算是文檔流的話)刪掉,無(wú)法進(jìn)行繪制,所以比較好的做法就是用一個(gè) cover-view進(jìn)行覆蓋

  • 將繪制好的 canvas輸出為 圖片

canvas繪制好后,將其繪制成圖片保存在本地臨時(shí)存儲(chǔ)中,可以拿到這個(gè)圖片在本地的臨時(shí)路徑,然后將這張圖片放到頁(yè)面上,并給這張圖片設(shè)置尺寸樣式,圖片的寬度等于設(shè)備的寬度,高度跟隨寬度進(jìn)行等比例縮放,最終讓用戶看到的就是這張圖片,因?yàn)檫M(jìn)行了等比例縮放,所以視覺(jué)效果就是和設(shè)計(jì)圖上是一樣的

這里也有幾個(gè)點(diǎn)需要注意下

  • ctx.draw是異步操作

一直以為這個(gè)方法是同步方法,所以調(diào)用完此方法后立即輸出圖片,就出現(xiàn)了有時(shí)候圖片錯(cuò)誤的情況,后來(lái)才發(fā)現(xiàn)這個(gè)是異步操作,這就是看文檔不仔細(xì)的后果

ctx.draw(false, () => {
  // 保存為本地臨時(shí)文件
  this.saveImageToLocal()
})
復(fù)制代碼
  • 繪制 canvas階段,要允許頁(yè)面橫向溢出

由于一開始繪制 canvas是按照iphone6的標(biāo)準(zhǔn)進(jìn)行的,所以在有些寬度小于 iphone6的設(shè)備上,canvas的寬度是可能會(huì)比設(shè)備的寬度要大的(如果你繪制的是整屏 canvas),但是小程序頁(yè)面的根元素 page,默認(rèn)設(shè)置了 overflow-x: hiddne;,導(dǎo)致繪制不完整,所以需要覆蓋這個(gè)樣式:

page {
  overflow-x: scroll;
}
復(fù)制代碼
  • 繪制完畢后,避免頁(yè)面橫向溢出

當(dāng)上一步繪制完成 canvas后,并成功將圖片繪制到頁(yè)面上時(shí),如果當(dāng)前設(shè)備的寬度小于 iphone 6,又由于前面給 page元素設(shè)置了 overflow-x: scroll,所以此時(shí) canvas元素肯定會(huì)撐大頁(yè)面,讓頁(yè)面上出現(xiàn)一個(gè)橫向的滾動(dòng)條,而用戶看到的圖片寬度是和設(shè)備寬度相同,不應(yīng)該出現(xiàn)這種情況

解決方法,一種是直接使用 wx-if這種條件語(yǔ)句刪掉 canvas元素,但是在低版本的基礎(chǔ)庫(kù)上,可能會(huì)報(bào) e.canvasId is undefined的錯(cuò)誤(雖然根據(jù)實(shí)測(cè)來(lái)看,似乎并不影響正常功能) 第二種就是減少 canvas的尺寸,反正已經(jīng)繪制好圖片了,后面也用不到它了,而且用戶也看不到,那就可以隨意減小尺寸,我的做法是干脆無(wú)論寬高通通設(shè)為 0,免得又出現(xiàn)什么 bug

// 避免在尺寸小的設(shè)備上溢出
this.setData({
  canvasWidth: 0,
  canvasHeight: 0
})
復(fù)制代碼

以上,兩種方法都可以選擇,各有利弊,第一種要寫很多 rem轉(zhuǎn)換,第二種需要做的操作又比較多,各有利弊,根據(jù)真實(shí)需求進(jìn)行抉擇即可。


電話咨詢 預(yù)約演示 0元開店