Skip to content

Commit f3204fb

Browse files
committed
refactor: 优化FluCheckBox过渡效果
1 parent e303762 commit f3204fb

File tree

2 files changed

+184
-41
lines changed

2 files changed

+184
-41
lines changed

src/Qt5/imports/FluentUI/Controls/FluCheckBox.qml

Lines changed: 92 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ Button {
8686
}
8787
border.width: 1
8888
color: {
89-
if(checked){
89+
if(checked || indeterminate){
9090
if(!enabled){
9191
return checkedDisableColor
9292
}
@@ -106,29 +106,101 @@ Button {
106106
}
107107
return normalColor
108108
}
109-
FluIcon {
109+
Canvas {
110+
id: markCanvas
111+
property real strokeProgress: 0.0
112+
property color strokeColor: FluTheme.dark ? "#000000" : "#FFFFFF"
110113
anchors.centerIn: parent
111-
iconSource: FluentIcons.CheckboxIndeterminate
112-
iconSize: 14
113-
visible: indeterminate
114-
iconColor: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
115-
Behavior on visible {
116-
enabled: control.animationEnabled
117-
NumberAnimation{
118-
duration: 83
114+
width: size - 6
115+
height: width
116+
visible: state !== "unchecked"
117+
state: {
118+
if (!indeterminate && checked) {
119+
return "checked"
120+
} else if (indeterminate) {
121+
return "indeterminate"
119122
}
123+
return "unchecked"
120124
}
121-
}
122-
FluIcon {
123-
anchors.centerIn: parent
124-
iconSource: FluentIcons.AcceptMedium
125-
iconSize: 14
126-
visible: checked && !indeterminate
127-
iconColor: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
128-
Behavior on visible {
125+
states: [
126+
State {
127+
name: "checked"
128+
PropertyChanges {
129+
target: markCanvas
130+
strokeProgress: 1.0
131+
}
132+
},
133+
State {
134+
name: "indeterminate"
135+
PropertyChanges {
136+
target: markCanvas
137+
strokeProgress: 1.0
138+
}
139+
},
140+
State {
141+
name: "unchecked"
142+
PropertyChanges {
143+
target: markCanvas
144+
strokeProgress: 0.0
145+
}
146+
}
147+
]
148+
onStateChanged: {
149+
if (state !== "unchecked") {
150+
requestPaint()
151+
}
152+
}
153+
onStrokeProgressChanged: requestPaint()
154+
onStrokeColorChanged: requestPaint()
155+
onPaint: {
156+
const ctx = getContext("2d")
157+
ctx.clearRect(0, 0, width, height)
158+
ctx.save()
159+
ctx.strokeStyle = strokeColor
160+
ctx.lineWidth = 2.0
161+
ctx.lineCap = "round"
162+
ctx.lineJoin = "round"
163+
if (state === "checked") {
164+
// draw Accept
165+
const startX = width * 0.15, startY = height * 0.5
166+
const midX = width * 0.4, midY = height * 0.75
167+
const endX = width - startX, endY = height * 0.3
168+
const line1Width = Math.sqrt(Math.pow(midX - startX, 2) + Math.pow(midY - startY, 2))
169+
const line2Width = Math.sqrt(Math.pow(endX - midX, 2) + Math.pow(endY - midY, 2))
170+
const totalLen = line1Width + line2Width
171+
const drawLen = totalLen * strokeProgress
172+
ctx.beginPath()
173+
ctx.moveTo(startX, startY)
174+
// draw line 1
175+
if (drawLen >= line1Width) {
176+
ctx.lineTo(midX, midY)
177+
} else {
178+
const ratio = drawLen / line1Width
179+
ctx.lineTo(startX + (midX - startX) * ratio, startY + (midY - startY) * ratio)
180+
}
181+
// draw line 2
182+
if (drawLen > line1Width) {
183+
const ratio2 = (drawLen - line1Width) / line2Width
184+
ctx.lineTo(midX + (endX - midX) * ratio2, midY + (endY - midY) * ratio2)
185+
}
186+
} else if (state === "indeterminate") {
187+
// draw Indeterminate
188+
const totalWidth = width * 0.6
189+
const halfWidth = (totalWidth / 2) * strokeProgress
190+
const centerX = width / 2
191+
const centerY = height / 2
192+
ctx.beginPath()
193+
ctx.moveTo(centerX - halfWidth, centerY)
194+
ctx.lineTo(centerX + halfWidth, centerY)
195+
}
196+
ctx.stroke()
197+
ctx.restore()
198+
}
199+
Behavior on strokeProgress {
129200
enabled: control.animationEnabled
130-
NumberAnimation{
131-
duration: 83
201+
NumberAnimation {
202+
duration: 167
203+
easing.type: Easing.OutCubic
132204
}
133205
}
134206
}

src/Qt6/imports/FluentUI/Controls/FluCheckBox.qml

Lines changed: 92 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Button {
8787
}
8888
border.width: 1
8989
color: {
90-
if(checked){
90+
if(checked || indeterminate){
9191
if(!enabled){
9292
return checkedDisableColor
9393
}
@@ -107,30 +107,101 @@ Button {
107107
}
108108
return normalColor
109109
}
110-
FluIcon {
110+
Canvas {
111+
id: markCanvas
112+
property real strokeProgress: 0.0
113+
property color strokeColor: FluTheme.dark ? "#000000" : "#FFFFFF"
111114
anchors.centerIn: parent
112-
iconSource: FluentIcons.CheckboxIndeterminate
113-
iconSize: 14
114-
visible: indeterminate
115-
iconColor: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
116-
Behavior on visible {
117-
enabled: control.animationEnabled
118-
NumberAnimation{
119-
duration: 83
115+
width: size - 6
116+
height: width
117+
visible: state !== "unchecked"
118+
state: {
119+
if (!indeterminate && checked) {
120+
return "checked"
121+
} else if (indeterminate) {
122+
return "indeterminate"
120123
}
124+
return "unchecked"
121125
}
122-
}
123-
124-
FluIcon {
125-
anchors.centerIn: parent
126-
iconSource: FluentIcons.AcceptMedium
127-
iconSize: 14
128-
visible: checked && !indeterminate
129-
iconColor: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
130-
Behavior on visible {
126+
states: [
127+
State {
128+
name: "checked"
129+
PropertyChanges {
130+
target: markCanvas
131+
strokeProgress: 1.0
132+
}
133+
},
134+
State {
135+
name: "indeterminate"
136+
PropertyChanges {
137+
target: markCanvas
138+
strokeProgress: 1.0
139+
}
140+
},
141+
State {
142+
name: "unchecked"
143+
PropertyChanges {
144+
target: markCanvas
145+
strokeProgress: 0.0
146+
}
147+
}
148+
]
149+
onStateChanged: {
150+
if (state !== "unchecked") {
151+
requestPaint()
152+
}
153+
}
154+
onStrokeProgressChanged: requestPaint()
155+
onStrokeColorChanged: requestPaint()
156+
onPaint: {
157+
const ctx = getContext("2d")
158+
ctx.clearRect(0, 0, width, height)
159+
ctx.save()
160+
ctx.strokeStyle = strokeColor
161+
ctx.lineWidth = 2.0
162+
ctx.lineCap = "round"
163+
ctx.lineJoin = "round"
164+
if (state === "checked") {
165+
// draw Accept
166+
const startX = width * 0.15, startY = height * 0.5
167+
const midX = width * 0.4, midY = height * 0.75
168+
const endX = width - startX, endY = height * 0.3
169+
const line1Width = Math.sqrt(Math.pow(midX - startX, 2) + Math.pow(midY - startY, 2))
170+
const line2Width = Math.sqrt(Math.pow(endX - midX, 2) + Math.pow(endY - midY, 2))
171+
const totalLen = line1Width + line2Width
172+
const drawLen = totalLen * strokeProgress
173+
ctx.beginPath()
174+
ctx.moveTo(startX, startY)
175+
// draw line 1
176+
if (drawLen >= line1Width) {
177+
ctx.lineTo(midX, midY)
178+
} else {
179+
const ratio = drawLen / line1Width
180+
ctx.lineTo(startX + (midX - startX) * ratio, startY + (midY - startY) * ratio)
181+
}
182+
// draw line 2
183+
if (drawLen > line1Width) {
184+
const ratio2 = (drawLen - line1Width) / line2Width
185+
ctx.lineTo(midX + (endX - midX) * ratio2, midY + (endY - midY) * ratio2)
186+
}
187+
} else if (state === "indeterminate") {
188+
// draw Indeterminate
189+
const totalWidth = width * 0.6
190+
const halfWidth = (totalWidth / 2) * strokeProgress
191+
const centerX = width / 2
192+
const centerY = height / 2
193+
ctx.beginPath()
194+
ctx.moveTo(centerX - halfWidth, centerY)
195+
ctx.lineTo(centerX + halfWidth, centerY)
196+
}
197+
ctx.stroke()
198+
ctx.restore()
199+
}
200+
Behavior on strokeProgress {
131201
enabled: control.animationEnabled
132-
NumberAnimation{
133-
duration: 83
202+
NumberAnimation {
203+
duration: 167
204+
easing.type: Easing.OutCubic
134205
}
135206
}
136207
}

0 commit comments

Comments
 (0)