forked from UWillno/QmlCardRow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCardRow.qml
More file actions
174 lines (158 loc) · 5.91 KB
/
CardRow.qml
File metadata and controls
174 lines (158 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import QtQuick
Rectangle {
id:row
property alias model: repeater.model
// 卡片角度
property real ang: -30
// 卡片视觉宽度
property real visualWidth: getVisualWidth(ang)
// 拖动时的最大角度
property real maxAngle: -10
// 拖动时的最小角度
property real minAngle: -85
// 角度变化时的步长
property real angleStepSize: 5
// 卡片的大小
property real cardWidth: 200
property real cardHeight: 150
// 首张卡片的位置
property real firstX: 20
property real firstY: 40
// 首张卡片与次张卡片的间距
property real firstSpacing: visualWidth *2/3
// 横轴卡片间距
// property real spacingX: 25
property real spacingX : Math.max(25,(parent.width - visualWidth*count)/count)
// 纵轴卡片间距
property real spacingY: 10
// 上浮高度
property real drift: -cardHeight/5
// 模型长度
property int count: repeater.model.length
// 首长卡片的索引
property int firstItemIndex : 0
// 可以下拉信号
signal canPull(var cardItem)
// 取消下拉信号
signal cancelPull()
// 可以推送信号
signal canPush()
// 推送信号
signal pushing(var url)
// 启用图层和提高采样 抗锯齿
layer.enabled: true
layer.samples: 8
Repeater {
anchors.fill: parent
id:repeater
delegate: Card {
id:card
// 模型数据
required property var modelData
// repeater中的索引
required property int index
// 虚拟索引 用于计算实际位置
property int virtualIndex: index
width: cardWidth
height: cardHeight
image: modelData.img
// 根据虚拟索引判断在哪一层
z: parent.count - virtualIndex
x: firstX + spacingX*virtualIndex + firstSpacing * (virtualIndex >=1 ? 1 :0)
// 鼠标在里面时上浮
y: mouseArea.containsMouse ? firstY + spacingY*virtualIndex + drift : firstY + spacingY*virtualIndex
// 鼠标在里面且为首项时回正
angle:mouseArea.containsMouse && index === firstItemIndex ? 0: ang
content :modelData.text
// 边框
border.width: 4
border.color: "gray"
// 颜色梯度
gradient: logic.getRandomGradient()
MouseArea{
id:mouseArea
anchors.fill: parent
// 防止窃取
preventStealing: true
// 启用悬停
hoverEnabled: true
// 记录按住时y的坐标
property real yStart: 0
// 是否追踪
property bool tracing: false
// 按住不动信号触发的时间
pressAndHoldInterval: 500
onClicked: {
// 与第一个组件交换位置
const tempIndex = repeater.itemAt(firstItemIndex).virtualIndex
repeater.itemAt(firstItemIndex).virtualIndex = card.virtualIndex
card.virtualIndex = tempIndex
firstItemIndex = card.index
}
onPressAndHold: (mouse)=>{
tracing = true
yStart = mouse.y
}
onPositionChanged: (mouse)=>{
if ( !tracing ) return
// 有下移就发射canPull,否则发射canceclPull
if(mouse.y-yStart > 0){
canPull(card)
// 达到能push的下移距离 发射canPush
if(Math.abs(mouse.y-yStart) > cardHeight/2){
canPush()
}
}
else
cancelPull()
}
onReleased: (mouse)=>{
// 松开时达到push要求 就发射pushing
if(Math.abs(mouse.y-yStart) > cardHeight/2){
pushing(modelData.url)
}
// 还原
cancelPull()
tracing = false
}
}
}
}
MouseArea {
anchors.fill: parent
preventStealing: true
property real xStart: 0
property bool tracing: false
onPressed: (mouse)=>{
tracing = true
xStart = mouse.x
}
onPositionChanged: (mouse)=>{
if ( !tracing ) return
const displacement = mouse.x-xStart
if(displacement < 0 && Math.abs(displacement) > visualWidth/10){
cutAngle()
}else if(displacement > 0 && Math.abs(displacement) > visualWidth/10){
addAngle()
}
}
onReleased: (mouse)=>{
tracing = false
}
}
// 角度增加
function addAngle(){
if(ang!==maxAngle)
ang += angleStepSize
}
// 角度减少
function cutAngle(){
if(ang!==minAngle)
ang -= angleStepSize
}
// 计算视觉宽度
function getVisualWidth(angle) {
var radian = angle * Math.PI / 180;
return Math.abs(cardWidth * Math.cos(radian))
}
}