QML <2> Canvas 自定义绘制 网易云歌单封面实现
前言
基于QML 实现 网易云歌单封面,参考图如下:
实现图如下:
一、背景图
最底层为Rectangle ,图片用AnimatedImage 显示,`
Rectangle {
width: 200
height: 220
clip: true
property string msg: "26万"
AnimatedImage {
id: animatedImage
x: 0
y: 0
width: 200
height: 180
source: "qrc:/img/img/109951166294262909.jpg"
二、音乐图标
音乐图标,使用Unicode 字符显示,代码如下:
Unicode 字符获取网址:https://unicode-table.com/cn/blocks/
Text {
id: unicode_text
x: 8
y: 149
width: 19
height: 27
text: String.fromCodePoint(0x1D160)
layer.smooth: true
layer.wrapMode: ShaderEffectSource.ClampToEdge
transformOrigin: Item.Center
font.pixelSize: 28
color: "white"
}
三.播放量
播放量文字使用Canvas 绘制,代码如下:
property string msg: "26万"
Canvas{
id: msg_canvas
x: 23
y: 157
width: 138
height: 23
onPaint: {
var ctx = getContext("2d")
draw(ctx)
}
function draw(ctx )
{
ctx.fillStyle = "white";
ctx.lineWidth = 2;
ctx.font="18px Georgia";
ctx.beginPath();
ctx.fillText(msg, 15,15,width);
ctx.stroke();
}
}
四.播放图标
播放图标使用Canvas 绘制,由三角形和圆形组成,
代码如下(示例):
Canvas{
id: paly_canvas
x: 167
y: 151
width: 25
height: width
onPaint: {
var ctx = getContext("2d")
draw(ctx)
}
function draw(ctx )
{
// 圆圈绘制
ctx.strokeStyle = "white"
ctx.lineWidth = 1
ctx.beginPath()
ctx.arc(width/2,height/2,width/2,0,Math.PI*2)
ctx.stroke()
//三角形绘制
ctx.fillStyle = "white"
ctx.strokeStyle = "white"
ctx.beginPath()
ctx.moveTo(width/4, height/4)
ctx.lineTo(width/4, height/4*3)
ctx.lineTo(width/4*3, height/2)
ctx.closePath()
ctx.fill()
ctx.stroke()
}
}
五.歌单信息背景
歌单信息背景使用Canvas 绘制,
代码如下:
Canvas{
id: msg_background
x: 0
y: 143
width: 200
height: 39
onPaint: {
var ctx = getContext("2d")
draw(ctx)
}
function draw(ctx )
{
ctx.clearRect(0, 0, width, height)
ctx.strokeStyle = "rgba(54, 54, 54, 0.4)";
ctx.fillStyle = "rgba(54, 54, 54, 0.4)";
ctx.fillRect(0, 0,parent.width, parent.height)
ctx.stroke()
}
}
六.歌单文字介绍
歌单文字介绍使用Canvas 绘制,可设置最多显示行数,超出行数使用“…”显示,代码如下:
Canvas{
id: name_canvas
x: 0
y: 181
width: 200
height: 39
onPaint: {
var ctx = getContext("2d");
ctx.fillStyle = "rgba(54, 54, 54, 1)";
ctx.lineWidth = 2;
ctx.font="14px Georgia";
var str= "今天温柔的风归功于昨天的雨"
draw_text_show(ctx,width-15,15,2,str);
}
}
//ctx 画布
// linewidth 行宽
// lineheight 行高
// maxline 最大行数
// str 显示字符串
function draw_text_show(ctx,linewidth,lineheight,maxline,str)
{
var strwidth = ctx.measureText(str).width;
if(strwidth < linewidth)
{
ctx.fillText(str, 5, lineheight);
}
else
{
var curwidth = 0;
var curline= 1;
var maskstr = '...';
var maskwidth = ctx.measureText(maskstr).width;
var curstr="";
var len = str.length;
for( var i = 0; i < str.length; ++i )
{
var fontWidth = ctx.measureText(str[i]).width;
var nextwidth = curwidth+fontWidth;
var draw_all = false;
//########
//####...
if(curline == maxline)
{
nextwidth += maskwidth;
if(nextwidth <= linewidth)
{
curwidth += fontWidth;
curstr += str[i];
if(i+1 < str.length)
{
continue;
}
}
else
{
curstr += maskstr;
draw_all = true;
console.log(curstr)
}
}
else
{
if( nextwidth <= linewidth )
{
curwidth += fontWidth;
curstr += str[i]
continue;
}
}
ctx.fillText(curstr, 5, lineheight*curline);
curline++;
curwidth = 0;
curstr="";
if(draw_all)
{
break;
}
}
}
}
总结
完整代码:
import QtQuick 2.12
Rectangle {
width: 200
height: 220
clip: true
property string msg: "26万"
AnimatedImage {
id: animatedImage
x: 0
y: 0
width: 200
height: 180
source: "qrc:/img/img/109951166294262909.jpg"
Canvas{
id: msg_background
x: 0
y: 143
width: 200
height: 39
onPaint: {
var ctx = getContext("2d")
draw(ctx)
}
function draw(ctx )
{
ctx.clearRect(0, 0, width, height)
ctx.strokeStyle = "rgba(54, 54, 54, 0.4)";
ctx.fillStyle = "rgba(54, 54, 54, 0.4)";
ctx.fillRect(0, 0,parent.width, parent.height)
ctx.stroke()
}
}
Text {
id: unicode_text
x: 8
y: 149
width: 19
height: 27
text: String.fromCodePoint(0x1D160)
layer.smooth: true
layer.wrapMode: ShaderEffectSource.ClampToEdge
transformOrigin: Item.Center
font.pixelSize: 28
color: "white"
}
Canvas{
id: msg_canvas
x: 23
y: 157
width: 138
height: 23
onPaint: {
var ctx = getContext("2d")
draw(ctx)
}
function draw(ctx )
{
ctx.fillStyle = "white";
ctx.lineWidth = 2;
ctx.font="18px Georgia";
ctx.beginPath();
ctx.fillText(msg, 15,15,width);
ctx.stroke();
}
}
Canvas{
id: paly_canvas
x: 167
y: 151
width: 25
height: width
onPaint: {
var ctx = getContext("2d")
draw(ctx)
}
function draw(ctx )
{
// 圆圈绘制
ctx.strokeStyle = "white"
ctx.lineWidth = 1
ctx.beginPath()
ctx.arc(width/2,height/2,width/2,0,Math.PI*2)
ctx.stroke()
//三角形绘制
ctx.fillStyle = "white"
ctx.strokeStyle = "white"
ctx.beginPath()
ctx.moveTo(width/4, height/4)
ctx.lineTo(width/4, height/4*3)
ctx.lineTo(width/4*3, height/2)
ctx.closePath()
ctx.fill()
ctx.stroke()
}
}
}
Canvas{
id: name_canvas
x: 0
y: 181
width: 200
height: 39
onPaint: {
var ctx = getContext("2d");
ctx.fillStyle = "rgba(54, 54, 54, 1)";
ctx.lineWidth = 2;
ctx.font="14px Georgia";
var str= "今天温柔的风归功于昨天的雨今天温柔的风归功于昨天的雨今天温柔的风归功于昨天的雨"
draw_text_show(ctx,width-15,15,2,str);
}
}
//ctx 画布
// linewidth 行宽
// lineheight 行高
// maxline 最大行数
// str 显示字符串
function draw_text_show(ctx,linewidth,lineheight,maxline,str)
{
var strwidth = ctx.measureText(str).width;
if(strwidth < linewidth)
{
ctx.fillText(str, 5, lineheight);
}
else
{
var curwidth = 0;
var curline= 1;
var maskstr = '...';
var maskwidth = ctx.measureText(maskstr).width;
var curstr="";
var len = str.length;
for( var i = 0; i < str.length; ++i )
{
var fontWidth = ctx.measureText(str[i]).width;
var nextwidth = curwidth+fontWidth;
var draw_all = false;
//########
//####...
if(curline == maxline)
{
nextwidth += maskwidth;
if(nextwidth <= linewidth)
{
curwidth += fontWidth;
curstr += str[i];
if(i+1 < str.length)
{
continue;
}
}
else
{
curstr += maskstr;
draw_all = true;
console.log(curstr)
}
}
else
{
if( nextwidth <= linewidth )
{
curwidth += fontWidth;
curstr += str[i]
continue;
}
}
ctx.fillText(curstr, 5, lineheight*curline);
curline++;
curwidth = 0;
curstr="";
if(draw_all)
{
break;
}
}
}
}
}