简体   繁体   English

动画自定义开关按钮

[英]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.为此,我使用了KeyValueKeyFrame

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM