微信小程序海報(bào)繪制示例講解
前言
海報(bào)分享功能在許多應(yīng)用中應(yīng)該是很常見(jiàn)的,因?yàn)樗鳛橐环N常用的應(yīng)用推廣和拉新的方式。
接下來(lái)看個(gè)實(shí)際的案例,如下:
把任務(wù)拆解下:
- 如何繪制海報(bào)
- 如何把繪制后的海報(bào)保存到相冊(cè)
繪制海報(bào)
用 canvas
來(lái)繪制海報(bào)。 這里需要了解基本的 canvas api
,不熟悉可以先去了解下相關(guān) Canvas API
定義 canvas
元素
<template> <view class="poster-container"> <canvas class="poster" canvas-id="posterId"></canvas> <button class="btn" @click="onSave">保存至相冊(cè)</button> </view> </template>
獲取 canvas
上下文對(duì)象
const context = uni.createCanvasContext('posterId');
繪制背景圖片
圖片支持遠(yuǎn)程圖片和本地圖片,網(wǎng)絡(luò)圖片要通過(guò) getImageInfo
/ downloadFile
先下載。
context.drawImage('/static/poster.png', 0, 0, 320, 410); // 繪制背景圖片
繪制頭像和昵稱(chēng)
const avatarLeft = 185; const avatarTop = 18; const avatarWidth = 16; const avatarHeight = 16; context.drawImage( '/static/avatar.png', avatarLeft, avatarTop, avatarWidth, avatarHeight );
從設(shè)計(jì)上來(lái)看頭像和昵稱(chēng)是對(duì)齊的。
直接按照設(shè)計(jì)稿距離來(lái)設(shè)定看看效果
const nickName = '墻頭草中的頂尖的'; const nameLeft = avatarLeft + avatarWidth + 7; context.setFillStyle('#ffffff'); context.setFontSize(12); context.fillText(nickName, nameLeft, 21, 96);
實(shí)際效果如下:
發(fā)現(xiàn)與預(yù)期效果對(duì)應(yīng)不上,思考下這是為什么? 文字設(shè)置距離偏移的參考基線(xiàn)不是文字的頂部。
怎么驗(yàn)證我的說(shuō)法呢?可以 x
值設(shè)置為 0
。
const nickName = '墻頭草中的頂尖的'; const nameLeft = avatarLeft + avatarWidth + 7; context.setFillStyle('#ffffff'); context.setFontSize(12); context.fillText(nickName, nameLeft, 0, 96); // 修改為 0
再看看效果:
發(fā)現(xiàn)參考點(diǎn)幾乎是文字的底部,這就驗(yàn)證了上面的結(jié)論。
怎么解決這個(gè)問(wèn)題呢?
- 獲取文本行的高度
- 更改偏移的參考點(diǎn)
通常知道文本行實(shí)際占用的高度,需要知道其 line-height
,上面并不知道其 line-height
值。canvas
本身并不直接支持line-height
屬性,顯然沒(méi)辦法獲得相對(duì)準(zhǔn)確的行高。
只能采用第二種方式,從 canvas
提供 API 來(lái)看,可以更改文本相行對(duì)齊的點(diǎn)。
const nickName = '墻頭草中的頂尖的'; const nameLeft = avatarLeft + avatarWidth + 7; context.setFillStyle('#ffffff'); context.setFontSize(12); context.setTextBaseline('top'); // 更改基線(xiàn)對(duì)齊點(diǎn) context.fillText(nickName, nameLeft, 21, 96);
再來(lái)看看效果如下:
接下來(lái)實(shí)現(xiàn)二維碼區(qū)域,主要白色背景 + 二維碼 + 文案
白色背景區(qū)域
const rectWidth = 300; const rectHeight = 89; const rectLeft = 10; const rectTop = 311; context.setFillStyle('#ffffff'); context.fillRect(rectLeft, rectTop, rectWidth, rectHeight);
效果如下:
繪制二維碼
const qrcodeLeft = 20; const qrcodeTop = rectTop + 10; const qrcodeWidth = 68; const qrcodeHeight = 68; context.drawImage( '/static/qrcode.png', qrcodeLeft, qrcodeTop, qrcodeWidth, qrcodeHeight );
二維碼這里直接采用現(xiàn)成圖片。實(shí)際上前端可以通過(guò) weapp.qrcode.esm.js
在前端生成二維碼,再把它繪制上去。
繪制多行文本
const startX = qrcodeLeft + qrcodeWidth + 15; const text1 = '與志同道合的,他們一起成長(zhǎng)'; context.setFillStyle('#161413'); context.setFontSize(14); context.setTextBaseline('top'); context.fillText(text1, startX, rectTop + 29); const text2 = '掃碼即可進(jìn)入“Get一下”社區(qū)'; context.font = 'bold 14px Arial'; context.fillText(text2, startX, rectTop + 51);
看看最后的效果:
左上角的部分沒(méi)有繪制,思路同頭像和昵稱(chēng)一樣。 接下來(lái)只要把圖片保存到相冊(cè)即可。
保存到相冊(cè)
在小程序中,提供方法支持如下:
const onSave = () => { // 轉(zhuǎn)換為臨時(shí)路徑 uni.canvasToTempFilePath({ canvasId: 'posterId', success: (res) => { // 保存圖片到相冊(cè) uni.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: () => { uni.showToast({ title: '保存成功', icon: 'none', }); }, fail: () => { uni.showToast({ title: '保存失敗', icon: 'none', }); }, }); }, }); };
這里基本上把一個(gè)海報(bào)繪制
擴(kuò)展
在繪制名稱(chēng)時(shí),用戶(hù)名稱(chēng)長(zhǎng)短不一至,如果名字過(guò)長(zhǎng)時(shí)會(huì)出現(xiàn)什么效果呢
const nickName = '墻頭草中的頂尖的墻頭草中的頂尖的'; const nameLeft = avatarLeft + avatarWidth + 7; context.setFillStyle('#ffffff'); context.setFontSize(12); context.fillText(nickName, nameLeft, 21, 96);
從效果來(lái)看,發(fā)現(xiàn)文字直接重疊。如果希望超出的部分能夠通過(guò)省略號(hào)來(lái)省略,是可以的
const nickName = '墻頭草中的頂尖的墻頭草中的頂尖的'; const nameLeft = avatarLeft + avatarWidth + 7; context.setFillStyle('#ffffff'); context.setFontSize(12); context.fillText(nickName, nameLeft, 21, 96); let text = ''; const textArr = nickName.split(''); const ellipsisWidth = context.measureText('...').width; // 省略號(hào)的寬度 for (let i = 0; i < textArr.length; i++) { const temp = text + textArr[i]; const metrics = context.measureText(temp); if (metrics.width + ellipsisWidth > 96) { text = text + '...'; break; } text = temp; } context.fillText(text, nameLeft, 21, 96);
上面主要是通過(guò) measureText
方法獲得文字對(duì)應(yīng)寬度,針對(duì)超出的部分采用省略號(hào)替代。當(dāng)然,如果希望完整地顯示名字,也可以使用換行的方式。具體的實(shí)現(xiàn)方式,就留給大家自己思考和實(shí)現(xiàn)了。
處理后效果如下:
頭像實(shí)現(xiàn)圓角
默認(rèn)采用圓角頭像,如果用戶(hù)上傳的頭像沒(méi)有進(jìn)行裁剪處理,導(dǎo)致圖片出現(xiàn)非圓角情況,那么在海報(bào)上呈現(xiàn)的效果可能會(huì)有所差異。
先使用一個(gè)非圓角的圖片,代碼修改如下:
const avatarLeft = 185; const avatarTop = 18; const avatarWidth = 16; const avatarHeight = 16; context.drawImage( '/static/avatar-rect.png', avatarLeft, avatarTop, avatarWidth, avatarHeight );
效果如下:
現(xiàn)在對(duì)圖片處理一下:
const avatarLeft = 185; const avatarTop = 18; const avatarWidth = 16; const avatarHeight = 16; context.beginPath(); context.arc( avatarLeft + avatarWidth / 2, avatarTop + avatarHeight / 2, avatarWidth / 2, 0, 2 * Math.PI ); context.closePath(); context.clip(); // 繪制圓形頭像 context.drawImage( '/static/avatar-rect.png', avatarLeft, avatarTop, avatarWidth, avatarHeight );
效果如下:
圓角是實(shí)現(xiàn)了,發(fā)現(xiàn)其他區(qū)域內(nèi)容都被裁剪了。 這是為什么? clip()
改變了繪畫(huà)環(huán)境。ctx()
調(diào)用后,所裁剪的區(qū)域就是 clip ()
后的繪制環(huán)境,clip()
之后的繪畫(huà)只能在裁剪區(qū)域中渲染,不能訪(fǎng)問(wèn)畫(huà)布上的其他區(qū)域。
怎么處理這個(gè)問(wèn)題呢 ? 通過(guò) save()
和 restore()
.
context.save(); // 暫存 context.beginPath(); context.arc( avatarLeft + avatarWidth / 2, avatarTop + avatarHeight / 2, avatarWidth / 2, 0, 2 * Math.PI ); context.closePath(); context.clip(); // 繪制圓形頭像 context.drawImage( '/static/avatar-rect.png', avatarLeft, avatarTop, avatarWidth, avatarHeight ); context.restore(); // 恢復(fù)
效果如下:
總結(jié)
- 通過(guò)
canvas
+ 小程序提供 API 實(shí)現(xiàn)海報(bào)繪制、保存海報(bào)到相冊(cè) - 優(yōu)化特殊情況下名稱(chēng)和頭像的展示方式。
以上就是微信小程序海報(bào)繪制示例講解的詳細(xì)內(nèi)容,更多關(guān)于小程序海報(bào)繪制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于JavaScript實(shí)現(xiàn)樹(shù)形下拉框
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)樹(shù)形下拉框的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08微信小程序?qū)崿F(xiàn)音樂(lè)播放頁(yè)面布局
這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)京東商品分類(lèi)側(cè)邊欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12原生js提示框并自動(dòng)關(guān)閉(手工關(guān)閉)
今天在寫(xiě)后臺(tái)交互的時(shí)候原來(lái)都是用alert太難看每次都需要點(diǎn)擊一下才可以,比較麻煩所以特整理了幾個(gè)比較好的js提示框代碼,方便提示一下2023-04-04微信小程序中實(shí)現(xiàn)手指縮放圖片的示例代碼
本篇文章主要介紹了微信小程序中實(shí)現(xiàn)手指縮放圖片的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03在Z-Blog中運(yùn)行代碼[html][/html](純JS版)
在Z-Blog中運(yùn)行代碼[html][/html](純JS版)...2007-03-03JS中正則表達(dá)式只有3種匹配模式(沒(méi)有單行模式)詳解
下面小編就為大家?guī)?lái)一篇JS中正則表達(dá)式只有3種匹配模式(沒(méi)有單行模式)詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07利用JavaScript差集實(shí)現(xiàn)一個(gè)對(duì)比小工具
這篇文章主要給大家介紹了關(guān)于利用JavaScript差集實(shí)現(xiàn)一個(gè)對(duì)比小工具的相關(guān)資料,雖然實(shí)現(xiàn)的界面不是太好看,但好在功能實(shí)用即可,需要的朋友可以參考下2021-07-07