Skip to content

Commit 704eb32

Browse files
authored
优化 JFXSpinner 动画生成逻辑 (#5804)
1 parent 730d9b4 commit 704eb32

File tree

1 file changed

+67
-123
lines changed

1 file changed

+67
-123
lines changed

HMCL/src/main/java/com/jfoenix/skins/JFXSpinnerSkin.java

Lines changed: 67 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@
2626
import javafx.animation.KeyValue;
2727
import javafx.animation.Timeline;
2828
import javafx.scene.Group;
29-
import javafx.scene.control.ProgressIndicator;
3029
import javafx.scene.control.SkinBase;
3130
import javafx.scene.layout.Region;
3231
import javafx.scene.layout.StackPane;
3332
import javafx.scene.paint.Color;
34-
import javafx.scene.paint.Paint;
3533
import javafx.scene.shape.Arc;
3634
import javafx.scene.shape.Rectangle;
3735
import javafx.scene.shape.StrokeLineCap;
3836
import javafx.util.Duration;
37+
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
38+
39+
import java.util.ArrayList;
40+
import java.util.List;
3941

4042
/// JFXSpinner material design skin
4143
///
@@ -46,11 +48,6 @@ public class JFXSpinnerSkin extends SkinBase<JFXSpinner> {
4648

4749
private static final double DEFAULT_STROKE_WIDTH = 4;
4850

49-
private static final Color GREEN_COLOR = Color.valueOf("#0F9D58");
50-
private static final Color RED_COLOR = Color.valueOf("#db4437");
51-
private static final Color YELLOW_COLOR = Color.valueOf("#f4b400");
52-
private static final Color BLUE_COLOR = Color.valueOf("#4285f4");
53-
5451
private JFXSpinner control;
5552
private final TreeShowingProperty treeShowingProperty;
5653
private boolean isValid = false;
@@ -60,7 +57,6 @@ public class JFXSpinnerSkin extends SkinBase<JFXSpinner> {
6057
private Arc track;
6158
private final StackPane arcPane;
6259
private final Rectangle fillRect;
63-
private double arcLength = -1;
6460

6561
private final double startingAngle;
6662

@@ -73,7 +69,6 @@ public JFXSpinnerSkin(JFXSpinner control) {
7369

7470
arc = new Arc();
7571
arc.setManaged(false);
76-
arc.setStartAngle(0);
7772
arc.setLength(180);
7873
arc.getStyleClass().setAll("arc");
7974
arc.setFill(Color.TRANSPARENT);
@@ -82,7 +77,6 @@ public JFXSpinnerSkin(JFXSpinner control) {
8277

8378
track = new Arc();
8479
track.setManaged(false);
85-
track.setStartAngle(0);
8680
track.setLength(360);
8781
track.setStrokeWidth(DEFAULT_STROKE_WIDTH);
8882
track.getStyleClass().setAll("track");
@@ -97,72 +91,28 @@ public JFXSpinnerSkin(JFXSpinner control) {
9791
getChildren().setAll(arcPane);
9892

9993
// register listeners
100-
registerChangeListener(control.indeterminateProperty(), obs -> initialize());
10194
registerChangeListener(control.progressProperty(), obs -> updateProgress());
102-
registerChangeListener(treeShowingProperty, obs -> updateAnimation());
103-
registerChangeListener(control.sceneProperty(), obs -> updateAnimation());
95+
registerChangeListener(treeShowingProperty, obs -> updateProgress());
10496
}
10597

106-
private void initialize() {
107-
if (getSkinnable().isIndeterminate()) {
108-
if (timeline == null) {
109-
createTransition();
110-
if (treeShowingProperty.get()) {
98+
private void updateProgress() {
99+
double progress = Double.min(getSkinnable().getProgress(), 1.0);
100+
if (progress < 0) { // indeterminate
101+
boolean treeShowing = treeShowingProperty.get();
102+
if (treeShowing) {
103+
if (timeline == null) {
104+
timeline = createTransition();
105+
timeline.playFromStart();
106+
} else {
111107
timeline.play();
112108
}
109+
} else if (timeline != null) {
110+
timeline.pause();
113111
}
114-
} else {
112+
} else { // determinate
115113
clearAnimation();
116114
arc.setStartAngle(90);
117-
updateProgress();
118-
}
119-
}
120-
121-
private KeyFrame[] getKeyFrames(double angle, double duration, Paint color) {
122-
KeyFrame[] frames = new KeyFrame[4];
123-
frames[0] = new KeyFrame(Duration.seconds(duration),
124-
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
125-
new KeyValue(arc.startAngleProperty(),
126-
angle + 45 + startingAngle,
127-
Interpolator.LINEAR));
128-
frames[1] = new KeyFrame(Duration.seconds(duration + 0.4),
129-
new KeyValue(arc.lengthProperty(), 250, Interpolator.LINEAR),
130-
new KeyValue(arc.startAngleProperty(),
131-
angle + 90 + startingAngle,
132-
Interpolator.LINEAR));
133-
frames[2] = new KeyFrame(Duration.seconds(duration + 0.7),
134-
new KeyValue(arc.lengthProperty(), 250, Interpolator.LINEAR),
135-
new KeyValue(arc.startAngleProperty(),
136-
angle + 135 + startingAngle,
137-
Interpolator.LINEAR));
138-
frames[3] = new KeyFrame(Duration.seconds(duration + 1.1),
139-
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
140-
new KeyValue(arc.startAngleProperty(),
141-
angle + 435 + startingAngle,
142-
Interpolator.LINEAR),
143-
new KeyValue(arc.strokeProperty(), color, Interpolator.EASE_BOTH));
144-
return frames;
145-
}
146-
147-
private void pauseTimeline(boolean pause) {
148-
if (getSkinnable().isIndeterminate()) {
149-
if (timeline == null) {
150-
createTransition();
151-
}
152-
if (pause) {
153-
timeline.pause();
154-
} else {
155-
timeline.play();
156-
}
157-
}
158-
}
159-
160-
private void updateAnimation() {
161-
final boolean isTreeShowing = treeShowingProperty.get();
162-
if (timeline != null) {
163-
pauseTimeline(!isTreeShowing);
164-
} else if (isTreeShowing) {
165-
createTransition();
115+
arc.setLength(-360 * progress);
166116
}
167117
}
168118

@@ -222,13 +172,9 @@ protected void layoutChildren(double contentX, double contentY, double contentWi
222172
fillRect.setHeight(arcSize);
223173

224174
if (!isValid) {
225-
initialize();
175+
updateProgress();
226176
isValid = true;
227177
}
228-
229-
if (!getSkinnable().isIndeterminate()) {
230-
arc.setLength(arcLength);
231-
}
232178
}
233179

234180
private void updateArcLayout(double radius, double arcSize) {
@@ -244,66 +190,64 @@ private void updateArcLayout(double radius, double arcSize) {
244190
track.setStrokeWidth(arc.getStrokeWidth());
245191
}
246192

247-
boolean wasIndeterminate = false;
248-
249-
protected void updateProgress() {
250-
final ProgressIndicator control = getSkinnable();
251-
final boolean isIndeterminate = control.isIndeterminate();
252-
if (!(isIndeterminate && wasIndeterminate)) {
253-
arcLength = -360 * control.getProgress();
254-
control.requestLayout();
255-
}
256-
wasIndeterminate = isIndeterminate;
257-
}
258-
259-
private void createTransition() {
260-
if (!getSkinnable().isIndeterminate()) return;
261-
final Paint initialColor = arc.getStroke();
262-
if (initialColor == null) {
263-
arc.setStroke(BLUE_COLOR);
264-
}
265-
266-
KeyFrame[] blueFrame = getKeyFrames(0, 0, initialColor == null ? BLUE_COLOR : initialColor);
267-
KeyFrame[] redFrame = getKeyFrames(450, 1.4, initialColor == null ? RED_COLOR : initialColor);
268-
KeyFrame[] yellowFrame = getKeyFrames(900, 2.8, initialColor == null ? YELLOW_COLOR : initialColor);
269-
KeyFrame[] greenFrame = getKeyFrames(1350, 4.2, initialColor == null ? GREEN_COLOR : initialColor);
270-
271-
KeyFrame endingFrame = new KeyFrame(Duration.seconds(5.6),
193+
private void addKeyFrames(List<KeyFrame> frames, double angle, double duration) {
194+
frames.add(new KeyFrame(Duration.seconds(duration),
272195
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
273196
new KeyValue(arc.startAngleProperty(),
274-
1845 + startingAngle,
275-
Interpolator.LINEAR));
197+
angle + 45 + startingAngle,
198+
Interpolator.LINEAR)));
199+
frames.add(new KeyFrame(Duration.seconds(duration + 0.4),
200+
new KeyValue(arc.lengthProperty(), 250, Interpolator.LINEAR),
201+
new KeyValue(arc.startAngleProperty(),
202+
angle + 90 + startingAngle,
203+
Interpolator.LINEAR)));
204+
frames.add(new KeyFrame(Duration.seconds(duration + 0.7),
205+
new KeyValue(arc.lengthProperty(), 250, Interpolator.LINEAR),
206+
new KeyValue(arc.startAngleProperty(),
207+
angle + 135 + startingAngle,
208+
Interpolator.LINEAR)));
209+
frames.add(new KeyFrame(Duration.seconds(duration + 1.1),
210+
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
211+
new KeyValue(arc.startAngleProperty(),
212+
angle + 435 + startingAngle,
213+
Interpolator.LINEAR)));
214+
}
276215

277-
if (timeline != null) {
278-
timeline.stop();
279-
timeline.getKeyFrames().clear();
216+
private Timeline createTransition() {
217+
Timeline timeline;
218+
if (AnimationUtils.isAnimationEnabled()) {
219+
var keyFrames = new ArrayList<KeyFrame>(17);
220+
addKeyFrames(keyFrames, 0, 0);
221+
addKeyFrames(keyFrames, 450, 1.4);
222+
addKeyFrames(keyFrames, 900, 2.8);
223+
addKeyFrames(keyFrames, 1350, 4.2);
224+
keyFrames.add(new KeyFrame(Duration.seconds(5.6),
225+
new KeyValue(arc.lengthProperty(), 5, Interpolator.LINEAR),
226+
new KeyValue(arc.startAngleProperty(),
227+
1845 + startingAngle,
228+
Interpolator.LINEAR)));
229+
230+
timeline = new Timeline();
231+
timeline.getKeyFrames().setAll(keyFrames);
232+
} else {
233+
final double arcLength = 250;
234+
timeline = new Timeline(
235+
new KeyFrame(Duration.ZERO,
236+
new KeyValue(arc.startAngleProperty(), 45 + startingAngle, Interpolator.LINEAR),
237+
new KeyValue(arc.lengthProperty(), arcLength, Interpolator.DISCRETE)),
238+
new KeyFrame(Duration.seconds(1.2),
239+
new KeyValue(arc.startAngleProperty(), 45 + 360 + startingAngle, Interpolator.LINEAR),
240+
new KeyValue(arc.lengthProperty(), arcLength, Interpolator.DISCRETE))
241+
);
280242
}
281-
timeline = new Timeline(blueFrame[0],
282-
blueFrame[1],
283-
blueFrame[2],
284-
blueFrame[3],
285-
redFrame[0],
286-
redFrame[1],
287-
redFrame[2],
288-
redFrame[3],
289-
yellowFrame[0],
290-
yellowFrame[1],
291-
yellowFrame[2],
292-
yellowFrame[3],
293-
greenFrame[0],
294-
greenFrame[1],
295-
greenFrame[2],
296-
greenFrame[3],
297-
endingFrame);
243+
298244
timeline.setCycleCount(Timeline.INDEFINITE);
299-
timeline.setDelay(Duration.ZERO);
300-
timeline.playFromStart();
245+
return timeline;
301246
}
302247

303248
private void clearAnimation() {
304249
if (timeline != null) {
305250
timeline.stop();
306-
timeline.getKeyFrames().clear();
307251
timeline = null;
308252
}
309253
}

0 commit comments

Comments
 (0)