海報分享功能在許多應(yīng)用中應(yīng)該是很常見的,因為它作為一種常用的應(yīng)用推廣和拉新的方式。
接下來看個實際的案例,如下:
把任務(wù)拆解下:
- 如何繪制海報
- 如何把繪制后的海報保存到相冊
繪制海報
用 canvas
來繪制海報。 這里需要了解基本的 canvas api
,不熟悉可以先去了解下相關(guān) Canvas API
- 定義
canvas
元素
<template>
<view class="poster-container">
<canvas class="poster" canvas-id="posterId"></canvas>
<button class="btn" @click="onSave">保存至相冊</button>
</view>
</template>
- 獲取
canvas
上下文對象
const context = uni.createCanvasContext('posterId');
- 繪制背景圖片
圖片支持遠程圖片
和本地圖片
,網(wǎng)絡(luò)圖片要通過 getImageInfo
/ downloadFile
先下載。
context.drawImage('/static/poster.png', 0, 0, 320, 410); // 繪制背景圖片
- 繪制頭像和昵稱
const avatarLeft = 185;
const avatarTop = 18;
const avatarWidth = 16;
const avatarHeight = 16;
context.drawImage(
'/static/avatar.png',
avatarLeft,
avatarTop,
avatarWidth,
avatarHeight
);
從設(shè)計上來看頭像和昵稱是對齊的。
直接按照設(shè)計稿距離來設(shè)定看看效果
const nickName = '墻頭草中的頂尖的';
const nameLeft = avatarLeft + avatarWidth + 7;
context.setFillStyle('#ffffff');
context.setFontSize(12);
context.fillText(nickName, nameLeft, 21, 96);
實際效果如下:
發(fā)現(xiàn)與預(yù)期效果對應(yīng)不上,思考下這是為什么? 文字設(shè)置距離偏移的參考基線不是文字的頂部。
怎么驗證我的說法呢?可以 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)參考點幾乎是文字的底部,這就驗證了上面的結(jié)論。
怎么解決這個問題呢?
- 獲取文本行的高度
- 更改偏移的參考點
通常知道文本行實際占用的高度,需要知道其 line-height
,上面并不知道其 line-height
值。canvas
本身并不直接支持line-height
屬性,顯然沒辦法獲得相對準確的行高。
只能采用第二種方式,從 canvas
提供 API 來看,可以更改文本相行對齊的點。
const nickName = '墻頭草中的頂尖的';
const nameLeft = avatarLeft + avatarWidth + 7;
context.setFillStyle('#ffffff');
context.setFontSize(12);
context.setTextBaseline('top'); // 更改基線對齊點
context.fillText(nickName, nameLeft, 21, 96);
再來看看效果如下:
接下來實現(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)成圖片。實際上前端可以通過 weapp.qrcode.esm.js
在前端生成二維碼,再把它繪制上去。
- 繪制多行文本
const startX = qrcodeLeft + qrcodeWidth + 15;
const text1 = '與志同道合的,他們一起成長';
context.setFillStyle('#161413');
context.setFontSize(14);
context.setTextBaseline('top');
context.fillText(text1, startX, rectTop + 29);
const text2 = '掃碼即可進入“Get一下”社區(qū)';
context.font = 'bold 14px Arial';
context.fillText(text2, startX, rectTop + 51);
看看最后的效果:
左上角的部分沒有繪制,思路同頭像和昵稱一樣。 接下來只要把圖片保存到相冊即可。
保存到相冊
在小程序中,提供方法支持如下:
const onSave = () => {
// 轉(zhuǎn)換為臨時路徑
uni.canvasToTempFilePath({
canvasId: 'posterId',
success: (res) => {
// 保存圖片到相冊
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.showToast({
title: '保存成功',
icon: 'none',
});
},
fail: () => {
uni.showToast({
title: '保存失敗',
icon: 'none',
});
},
});
},
});
};
這里基本上把一個海報繪制
擴展
- 在繪制名稱時,用戶名稱長短不一至,如果名字過長時會出現(xiàn)什么效果呢
const nickName = '墻頭草中的頂尖的墻頭草中的頂尖的';
const nameLeft = avatarLeft + avatarWidth + 7;
context.setFillStyle('#ffffff');
context.setFontSize(12);
context.fillText(nickName, nameLeft, 21, 96);
從效果來看,發(fā)現(xiàn)文字直接重疊。如果希望超出的部分能夠通過省略號來省略,是可以的
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; // 省略號的寬度
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);
上面主要是通過 measureText
方法獲得文字對應(yīng)寬度,針對超出的部分采用省略號替代。當然,如果希望完整地顯示名字,也可以使用換行的方式。具體的實現(xiàn)方式,就留給大家自己思考和實現(xiàn)了。
處理后效果如下:
- 頭像實現(xiàn)圓角
默認采用圓角頭像,如果用戶上傳的頭像沒有進行裁剪處理,導致圖片出現(xiàn)非圓角情況,那么在海報上呈現(xiàn)的效果可能會有所差異。
先使用一個非圓角的圖片,代碼修改如下:
const avatarLeft = 185;
const avatarTop = 18;
const avatarWidth = 16;
const avatarHeight = 16;
context.drawImage(
'/static/avatar-rect.png',
avatarLeft,
avatarTop,
avatarWidth,
avatarHeight
);
效果如下:
現(xiàn)在對圖片處理一下:
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
);
效果如下:
圓角是實現(xiàn)了,發(fā)現(xiàn)其他區(qū)域內(nèi)容都被裁剪了。 這是為什么? clip()
改變了繪畫環(huán)境。ctx()
調(diào)用后,所裁剪的區(qū)域就是 clip ()
后的繪制環(huán)境,clip()
之后的繪畫只能在裁剪區(qū)域中渲染,不能訪問畫布上的其他區(qū)域。
怎么處理這個問題呢 ? 通過 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ù)
效果如下:文章來源:http://www.zghlxwxcb.cn/news/detail-759633.html
總結(jié)
- 通過
canvas
+ 小程序提供 API 實現(xiàn)海報繪制、保存海報到相冊 - 優(yōu)化特殊情況下名稱和頭像的展示方式。
如果您有任何疑問,請隨時在評論區(qū)留言。文章來源地址http://www.zghlxwxcb.cn/news/detail-759633.html
到了這里,關(guān)于手把手教你繪制小程序海報的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!