自定义开关按钮动画

2023-12-31

我用的是定制的开关按钮 in the 自定义开关按钮 https://stackoverflow.com/questions/30593193/creating-sliding-on-off-switch-button-in-javafx#answer-57290206回答。现在我想animate the circle部分当用户toggles两个值(状态)之间。我用了KeyValue and KeyFrame为了这样做。

我添加到 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();

我怎样才能制作动画?


您可以使用翻译转换 https://openjfx.io/javadoc/18/javafx.graphics/javafx/animation/TranslateTransition.html,以动画方式移动轨道上开关的旋钮。

虽然与动画无关,但该解决方案也修改了原始示例 https://stackoverflow.com/questions/30593193/creating-sliding-on-off-switch-button-in-javafx#answer-57290206要在样式表中使用样式类,on伪类和暴露的on自定义控件的状态属性。

这个答案也是基于之前问题的想法的组合:

  • 在javaFX中创建滑动开/关开关按钮 https://stackoverflow.com/questions/30593193/creating-sliding-on-off-switch-button-in-javafx#answer-57290206
  • 根据模型状态更改 JavaFX 样式类 https://stackoverflow.com/questions/36094736/change-javafx-style-class-based-on-model-state

相关问题:

  • 一个控制多个点击监听器 https://stackoverflow.com/questions/73043337/one-control-many-click-listeners/73043974#73043974

示例代码

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-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");
}

建议进一步改进

可以对控件进行一些其他增强,这些增强与原始问题无关,但会提高控件的质量和可重用性。许多应用程序不需要这些增强功能,而且这些增强功能可能会增加实现的额外复杂性,而这对于这些应用程序来说是不必要的。

在此解决方案中,控件大小仍然是硬编码的,但如果愿意,您可以修改控件以使用基于em大小(类似于标准 JavaFX 控件)。

此外,此解决方案中未提供,您可以利用 JavaFX CSS 查找和派生颜色来使控件与为默认 Java 定义的颜色方案相匹配modena.css样式表,以便设置,例如-fx-base将应用程序的颜色设置为不同的值将更改此控件的颜色方案,就像标准控件一样。

内置控件使用Skin https://openjfx.io/javadoc/18/javafx.controls/javafx/scene/control/Skin.html抽象将公共 API 与控件 UI 的内部实现分开,以便用户可以分配自定义外观来完全更改控件的 UI。从概念上讲,该开关实际上是一种切换按钮,因此可以将其实现为可应用于现有 ToggleButton 控件的自定义外观,而不是使用自定义控件。或者,不太可取的是,因为它更加冗余,您可以在此处采用 Switch 实现,并将其拆分为一个扩展公共 API 的 Control 的 Switch 类和一个扩展 UI 和行为实现的 Skin 的 SwitchSkin 类。

替代实施

在采用此答案中链接的其他解决方案或此答案中的解决方案之前,对于像开关这样的相当常见的控件,请考虑使用来自 JavaFX 框架核心控件的现成控件或来自第三方库。通常,这些基于库的控件比您自己创建或在论坛和问答帖子中找到的控件质量更高。

对于这个特定的动画开关控件,材质FX https://github.com/palexdev/MaterialFX#documentation图书馆有一个特别好的实施 https://camo.githubusercontent.com/77ad469b3d74a12add42ac154f864cae42f1af4074af9350263c06abd5080a3a/68747470733a2f2f696d6775722e636f6d2f417255684835382e676966,由额外的金光闪闪提供动力:-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义开关按钮动画 的相关文章

随机推荐

  • gcc 命令中 -fsyntax-only 选项有什么用?

    我读到了关于 fsyntax only选项中gcc命令的手册页 我知道它显示丢失头文件的错误 并且忽略用户编码错误 我需要知道我的理解是否正确 我也需要更多地了解这个选项 那么有人可以解释一下这个选项吗 fsyntax only防止编译器生
  • 为什么不能在drawRect中改变UIView的背景颜色?

    理论上 您可以通过以下方式轻松设置背景颜色 self backgroundColor UIColor redColor 在drawRect中 但这没有任何效果 您可以更改视图的大小 边框 子视图等 但不能更改背景颜色 类似的 SO 查询建议
  • 如何在 shell 脚本中的 curl 命令中传递变量

    我有一个curl命令 curl u USER ID PASSWORD X GET http blah gso woo com 8080 rest job execution job details job id 变量job id其中有一个值
  • Backbone.Collection 上的 toJSON#在哪里?

    我不知道为什么 但我无法让它工作 var friends new Backbone Collection name Athos job Musketeer name Porthos job Musketeer name Aramis job
  • 创建 COM 互操作类的实例

    我正在尝试使用 C 从我的程序中打开 CorelDRAW 到目前为止 我已经能够通过引用适当的 com 库并调用来做到这一点 CorelDRAW Application draw new CorelDRAW Application draw
  • Python - ElementTree - 不能在元素上使用绝对路径

    当我尝试运行以下代码时 我在 ElementTree 中收到此错误 SyntaxError cannot use absolute path on element 我的 XML 文档如下所示
  • JSON 迭代器的类型安全警告

    我的问题来自于从 JSONObject 获取迭代器 最简单形式的代码生成错误 String json client retrieveList JSONObject jsonList new JSONObject json Iterator
  • Java - 不可变数组线程安全

    我有一个关于 Java 内存模型的问题 这是一个呈现问题的简单类 public class ImmutableIntArray private final int array public ImmutableIntArray array n
  • 如何有效地从 std::set 中选择随机元素

    如何有效地从一个随机元素中选择一个std set A std set iterator is 不是随机访问迭代器 所以我不能像为一个随机选择的元素那样直接索引std deque or std vector I could获取从返回的迭代器s
  • 表达式 lambda 和语句 lambda 之间的区别

    表达式 lambda 和语句 lambda 之间有区别吗 如果是这样 有什么区别 在下面的链接中找到了这个问题 但无法理解答案 什么是 Lambda 表达式 C 面试题 http csharpinterviewfaq blogspot in
  • MFMailComposeViewController 未从视图中消失

    我有以下代码 当调用操作表上的按钮时会调用该代码 但是 当我按取消 然后删除草稿时 它只是收费并且不会关闭 我在应用程序的其他地方使用相同的代码 并从选择的表格视图单元格中调用它 并且它可以在那里找到 有什么想法为什么它在这里不起作用吗 当
  • 当变量超出范围时是否意味着它不存在?

    我不确定我是否理解作用域 超出作用域的变量 我正在使用 Ruby 是否存在于内存中的某处 或者它是否停止存在 我知道你无法访问它 说超出范围的变量不再存在是不准确的吗 也许这是一个哲学问题 如果您使用托管语言 那么您不会分配和取消分配内存
  • Google Oauth2 userinfo API 不返回用户名数据

    在过去的几个月里 我一直在使用 OAuth 登录后使用此 url 来检索用户的名称和信息 https www googleapis com oauth2 v1 userinfo alt json 这给了我以下格式的 JSON id 1234
  • openGL以伪3D视角绘制扭曲的精灵(图像)

    好吧 这将是一个很难解释的事情 我正在使用 AndEngine 我认为是 openGL 为 Android 制作一个非常基本的 伪 3d 赛车游戏 我不相信使用 AndEngine 真的与这个问题有任何关系 因为我直接访问 openGL 函
  • UILocalizedIndexedCollat​​ion 仅返回英文排序规则

    我正在尝试使用以下方法获取像联系人这样的本地化索引UILocalizedIndexedCollation 在 通讯录 中 当我更改语言时 索引会更改以匹配语言 然而sectionIndexTitles始终返回英文索引 我已经用我创建的演示应
  • ValueError:“10.0.0.0/24”似乎不是 IPv4 或 IPv6 网络

    我想在 Python 中使用 IP 子网 IP 地址 我使用以下命令创建了 Python 代码ipaddress模块 当我在 pycharm IDE 中运行代码时 它工作正常 但是当我在命令提示符下键入时运行python test py 它
  • 如何使用 BEM 正确设置元素的范围?

    给定以下 BEM 树结构 其中存在五个嵌套级别 collection main features top story byline author 根据 BEM 的命名约定 其中一个元素是块的一部分 并且在它所属的块之外没有任何意义 命名该元
  • 什么是“别名”流缓冲区?

    什么是 别名流缓冲区 我在评论中遇到了这个词answer https stackoverflow com questions 3318714 check if ostream object is cout or ofstream c 331
  • 在后台接收 UIPasteboard (generalPasteboard) 通知

    有办法做到这一点吗 我注册我的对象UIPasteboardChangedNotification在启动时 但是当将其发送到后台并打开 例如 Safari 并复制一些文本时 我的处理程序永远不会被调用 我现在只使用模拟器 我都用过 NSNot
  • 自定义开关按钮动画

    我用的是定制的开关按钮 in the 自定义开关按钮 https stackoverflow com questions 30593193 creating sliding on off switch button in javafx an