QML动态标注线
1,目的
有些情况对某个位置进行标注,但是背景过于复杂, 需要将标注点和标注内容进行分离,这时就需要用到标注线。我们即明确知道了标注的的信息也让界面更加均衡。
效果图:
图1
图2
2,设计分析
如果单纯将标识点连线到标注区,这样在标注内容较多时是会给人杂乱不堪的感觉。这里我们先使用30度倾角拉出斜线,再使用水平画线延伸到目标点。后期在逻辑上控制斜线尽量不发生交叉,那么给人的感觉就较为整齐。
基本原理:我们已知信息是起始点、结束点坐标,首先通过起始点向结束的点的水平面画倾角30度的斜线,与结束点水平面重叠时转为画水平线直至结束坐标。
3,设计内容
首先在主qml中创建tagLine.qml组件,添加组件属性和基本元素。代码如下:
import QtQuick 2.0
Item {
id: tagLine
property point startPoint: Qt.point(0, 0)
property point endPoint: Qt.point(0, 0)
property var lineColor: "70ffe42f"
property var lineWidth: 1
//斜线长度
property var oblLineLength: 0
//水平线长度
property var horLineLength: 0
Rectangle{
id: oblLine
antialiasing: true
height: lineWidth
color: lineColor
transformOrigin: Item.TopLeft
}
Rectangle{
id: horLine
antialiasing: true
height: lineWidth
color: lineColor
transformOrigin: Item.TopLeft
}
}
从代码中可知 我们是使用rectangle作为线条进行绘制。现在基本元素已经齐全,下一步就是计算线条长度,和添加画线动画。
我们先实现线条长度计算函数。
首先我们需要了解界面的坐标系,水平方向右是x轴正向,垂直向下是y轴正向。
图3
在这个坐标系中,结束点可能会出现在起始点的如下4个区域中,我们先实现区域1中的计数,其他区域只需要在这个基础上稍微调整角度即可。
图4
下图5所示,我们最终需要的是a,c这两条线长。利用三角函数,已知b、f先算a=b/cos30°,d=btan30° 。下图是收藏的常用三角函数值表图6
图5
图6
这里还有一种情况就是d大于f的情况,这时我们就不能使用30度斜边改用垂线。实现代码如下
function drawCala() {
//相对角度
var angle= 0
//实际角度值
var realAngle = 0;
var newOblLeng = 0;
var newHorLeng = 0;
var tmpx = Math.abs(startPoint.x - endPoint.x);
var tmpy = Math.abs(startPoint.y - endPoint.y);
//情况1 30°夹角
if (tmpx >= Math.floor((Math.sqrt(3) / 3) tmpy))
{
newOblLeng = Math.floor(tmpy / (Math.sqrt(3) / 2));
newHorLeng = tmpx - Math.floor((Math.floor((Math.sqrt(3) / 3) tmpy)));
angle = 60;
}
//情况2 垂线和直线配合
else
{
newOblLeng = tmpy;
newHorLeng = tmpx;
angle = 90;
}
oblLine.width = newOblLeng;
horLine.width = newHorLeng;
}
到此我们已经计算出了这两根线的线长。还需要继续处理如下内容才算完成。
1,计算出c/a交汇的位置坐标,作为水平线c的起始点;
2,根据终点在起点的4个不同区域内,计算出线段a的倾角;
3,根据终点在起点的4个不同区域内,计算出水平线c的延伸方向;
4,添加动画,在a从起点开始延伸到达计算值后,水平线开始延伸,最终到达终点。
这里就不多说了,直接看代码吧,效果如下
图7
最终实现的代码:
tagLine.qml
import QtQuick 2.0
Item {
property point startPoint: Qt.point(0, 0)
property point endPoint: Qt.point(0, 0)
property var lineColor: "#70ffe42f"
property var lineWidth: 1
//斜线长度
property var oblLineLength: 0
//水平线长度
property var horLineLength: 0
onStartPointChanged: {
drawCala();
}
onEndPointChanged: {
drawCala();
}
function drawCala() {
//相对角度
var angle= 0
//实际角度值
var realAngle = 0;
var newOblLeng = 0;
var newHorLeng = 0;
var tmpx = Math.abs(startPoint.x - endPoint.x);
var tmpy = Math.abs(startPoint.y - endPoint.y);
//情况1 30°夹角
if (tmpx >= Math.floor((Math.sqrt(3) / 3) tmpy))
{
newOblLeng = Math.floor(tmpy / (Math.sqrt(3) / 2));
newHorLeng = tmpx - Math.floor((Math.floor((Math.sqrt(3) / 3) * tmpy)));
angle = 60;
}
//情况2 垂线和直线配合
else
{
newOblLeng = tmpy;
newHorLeng = tmpx;
angle = 90;
}
//水平线的Y坐标 和结束点Y坐标相同
horLine.y = endPoint.y;
//结束的点在起始点的左上方
if ((startPoint.x >= endPoint.x) (startPoint.y >= endPoint.y))
{
realAngle = 180 + angle;
horLine.x = endPoint.x + newHorLeng;
horLine.rotation = 180;
}
//结束的点在起始点的右上方
else if ((startPoint.x = endPoint.y))
{
realAngle = -angle;
horLine.x = endPoint.x - newHorLeng;
horLine.rotation = 0;
}
//结束的点在起始点的右下方
else if ((startPoint.x <= endPoint.x) (startPoint.y = endPoint.x) (startPoint.y 0)
{
oblAnimation.restart();
}
else
{
//当使用垂线时斜线长度清零
oblLine.width = oblLineLength;
//直接进行水平延伸
horLine.visible = true;
horAnimation.restart();
}
}
Rectangle{
id: oblLine
antialiasing: true
height: lineWidth
color: lineColor
transformOrigin: Item.TopLeft
}
Rectangle{
id: horLine
antialiasing: true
height: lineWidth
color: lineColor
transformOrigin: Item.TopLeft
}//代码效果参考:http://www.ezhiqi.com/zx/art_7400.html
PropertyAnimation {
id: oblAnimation
target: oblLine
property: "width"
duration: 500
from: 0
to: oblLineLength
onStopped: {
if (horLineLength > 0)
{
horLine.visible = true
horAnimation.restart()
}
}
onStarted: {
horLine.visible = false
}
}
PropertyAnimation {
id: horAnimation
target: horLine
property: "width"
duration: 600
from: 0
to: horLineLength
}
}
使用标注线main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
width: 480
height: 240
color: "#1f1f1f"
TagLine {
id: myTagLine
}
MouseArea {
anchors.fill: parent
onClicked: {
myTagLine.startPoint = Qt.point(parent.width / 2, parent.height / 2)
myTagLine.endPoint = Qt.point(50, 50)
}
}
}
4,总结
利用Rectangle组件进行画线,然后再进行动画拼接,最终实现线条延伸效果,此组件比较适合应用在标识内容较多的场合。后续还可以配合标识框的组合动画让效果更佳。对以上代码稍作调整可实现如图1,2的效果。
下来大家发现有什么问题或需要讨论交流,可以在简书、博客园、或邮箱将问题进行留言,我会及时回复和更新。
邮箱: whqcxz@163.com
原创: