[英]Animate custom switch button
I used the custom switch button in the custom SwitchButton answer.我在自定义 SwitchButton答案中使用了自定义开关按钮。 Now I would like to animate the circle part when the user toggles between the 2 values (state).
现在,当用户在两个值(状态)之间切换时,我想为圆形部分设置动画。 I used KeyValue and KeyFrame in order to do so.
为此,我使用了KeyValue和KeyFrame 。
The snippet of the animation that I added to the SwitchButton() method :我添加到 SwitchButton() 方法的动画片段:
KeyValue start = new KeyValue(button.alignmentProperty(), Pos.CENTER_RIGHT);
KeyValue end = new KeyValue(button.alignmentProperty(), Pos.CENTER_LEFT);
KeyFrame frame = new KeyFrame(Duration.seconds(4), start, end);
Timeline timeline = new Timeline(frame);
timeline.play();
How can I make the animation?如何制作动画?
You can use a TranslateTransition , to animate moving the knob for the switch on the track.您可以使用TranslateTransition来动画移动轨道上开关的旋钮。
Although unrelated to the animation, this solution also modifies the original example to use style classes in a stylesheet, an on
pseudo-class, and an exposed on
state property for the custom control.尽管与动画无关,但此解决方案还修改了原始示例以在样式表中使用样式类、
on
伪类和自定义控件on
公开状态属性。
Control sizes are still hardcoded in this solution, but if preferred, you could modify the control to use a system based on em
sizes (similar to the standard JavaFX controls).在此解决方案中,控件大小仍然是硬编码的,但如果愿意,您可以修改控件以使用基于
em
大小的系统(类似于标准 JavaFX 控件)。
This answer is also based on a combination of ideas from previous questions:这个答案也是基于先前问题的想法的组合:
Related question:相关问题:
Example Code示例代码
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.css.PseudoClass;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;
public class SwitchApp extends Application {
@Override
public void start(Stage stage) {
Switch lightSwitch = new Switch();
lightSwitch.onProperty().addListener((observable, wasOn, nowOn) -> {
System.out.println(nowOn ? "on" : "off");
});
StackPane layout = new StackPane(lightSwitch);
layout.setPadding(new Insets(30));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Switch extends StackPane {
private static final double TRACK_WIDTH = 30;
private static final double TRACK_HEIGHT = 10;
private static final double KNOB_DIAMETER = 15;
private static final Duration ANIMATION_DURATION = Duration.seconds(0.25);
public static final String CSS = "data:text/css," + // language=CSS
"""
.switch > .track {
-fx-fill: #ced5da;
}
.switch > .knob {
-fx-effect: dropshadow(
three-pass-box,
rgba(0,0,0,0.2),
0.2, 0.0, 0.0, 2
);
-fx-background-color: WHITE;
}
.switch:on > .track {
-fx-fill: #80C49E;
}
.switch:on > .knob {
-fx-effect: dropshadow(
three-pass-box,
rgba(0,0,0,0.2),
0.2, 0.0, 0.0, 2
);
-fx-background-color: #00893d;
}
""";
private final TranslateTransition onTransition;
private final TranslateTransition offTransition;
public Switch() {
// construct switch UI
getStylesheets().add(CSS);
getStyleClass().add("switch");
Rectangle track = new Rectangle(TRACK_WIDTH, TRACK_HEIGHT);
track.getStyleClass().add("track");
track.setArcHeight(track.getHeight());
track.setArcWidth(track.getHeight());
Button knob = new Button();
knob.getStyleClass().add("knob");
knob.setShape(new Circle(KNOB_DIAMETER / 2));
knob.setMaxSize(KNOB_DIAMETER, KNOB_DIAMETER);
knob.setMinSize(KNOB_DIAMETER, KNOB_DIAMETER);
knob.setFocusTraversable(false);
setAlignment(knob, Pos.CENTER_LEFT);
getChildren().addAll(track, knob);
setMinSize(TRACK_WIDTH, KNOB_DIAMETER);
// define animations
onTransition = new TranslateTransition(ANIMATION_DURATION, knob);
onTransition.setFromX(0);
onTransition.setToX(TRACK_WIDTH - KNOB_DIAMETER);
offTransition = new TranslateTransition(ANIMATION_DURATION, knob);
offTransition.setFromX(TRACK_WIDTH - KNOB_DIAMETER);
offTransition.setToX(0);
// add event handling
EventHandler<Event> click = e -> setOn(!isOn());
setOnMouseClicked(click);
knob.setOnMouseClicked(click);
onProperty().addListener((observable, wasOn, nowOn) -> updateState(nowOn));
updateState(isOn());
}
private void updateState(Boolean nowOn) {
onTransition.stop();
offTransition.stop();
if (nowOn != null && nowOn) {
onTransition.play();
} else {
offTransition.play();
}
}
public void setOn(boolean on) {
this.on.set(on);
}
public boolean isOn() {
return on.get();
}
public BooleanProperty onProperty() {
return on;
}
public BooleanProperty on =
new BooleanPropertyBase(false) {
@Override protected void invalidated() {
pseudoClassStateChanged(ON_PSEUDO_CLASS, get());
}
@Override public Object getBean() {
return Switch.this;
}
@Override public String getName() {
return "on";
}
};
private static final PseudoClass
ON_PSEUDO_CLASS = PseudoClass.getPseudoClass("on");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.