JavaFX 幻灯片动画闪烁



我有一个菜单,如果用户将鼠标悬停在WebView的前 3% 上,它会从场景顶部滑出,否则会占据场景的整个高度。我无法摆脱滑动动画中的"闪烁"。


以下是控制器的 FXML 的想法:

<fx:root type="javafx.scene.layout.StackPane" minHeight="768.0" minWidth="1024.0" xmlns:fx="http://javafx.com/fxml">
  <children>
    <WebView fx:id="wv" onKeyPressed="#onKeyDown" onMouseMoved="#onMouseMove" prefHeight="768.0" prefWidth="1024.0" />
    <VBox fx:id="vbox_slideview" fillWidth="true" maxHeight="326.0" maxWidth="1024.0" minHeight="326.0" minWidth="1024.0" prefHeight="326.0" prefWidth="1024.0" visible="false" StackPane.alignment="TOP_CENTER">
      ...
      <StackPane.margin>
       <Insets top="-326.0" />
      </StackPane.margin>
    </VBox>
  </children>
</fx:root>

请注意,root 元素是扩展StackPane的控制器类。

这是基本的 onMouseMove(现在我只想让它正确向下滑动(:

public void onMouseMove(MouseEvent e)
{
    if (e.getSceneY() < 0.03 * stage.getScene().getHeight())
    {
        this.vbox_slideview.setVisible(true);
        TimelineBuilder.create().keyFrames(
            new KeyFrame(
                Duration.millis(300),
                new KeyValue(this.vbox_slideview.layoutYProperty(),
                0)))
            .build().play();
    }
}

这闪烁,所以我添加一个"阻止机制"来阻止新动画运行,而另一个动画是一种方式:

Timeline    anim    = null;
boolean     blocked = false;
public boolean isBlocked()
{
    return blocked;
}
public void setBlocked(boolean blocked)
{
    this.blocked = blocked;
}
public void onMouseMove(MouseEvent e)
{
    if (isBlocked())
        return;
    setBlocked(true);
    if (e.getSceneY() < 0.03 * stage.getScene().getHeight())
    {
        this.vbox_slideview.setVisible(true);
        this.anim = TimelineBuilder.create().keyFrames(new KeyFrame(Duration.millis(300), new KeyValue(this.vbox_slideview.layoutYProperty(), 0))).build();
        this.anim.statusProperty().addListener(new ChangeListener<Status>() {
            @Override
            public void changed(ObservableValue<? extends Status> observableValue, Status oldValue, Status newValue)
            {
                if (newValue == Status.STOPPED)
                {
                    setBlocked(false);
                }
            }
        });
        this.anim.play();
        return;
    }
    setBlocked(false);
}

您会注意到我把动画放在一个类变量中。这是因为我尝试了其他几种阻止动画的方法,这些问题中的帖子建议:如何确定节点上是否已运行过渡?所有这些方法都提供相同的结果。

我还介绍了initialize()滑动菜单的 Y 属性的侦听器:

vbox_slideview.layoutYProperty().addListener(new ChangeListener<Number>() {
    @Override
    public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2)
    {
        System.out.println("y = " + arg0.getValue().intValue());
    }
});

结果很奇怪(强调我的(:

(Status == RUNNING)
y = -325
y = -308
y = -287
y = -269
y = -326 <<
y = -218
y = -326 <<
y = -196
y = -178
y = -326 <<
y = -158
y = -326 <<
y = -132
y = -120
y = -326 <<
y = -96
y = -326 <<
y = -76
y = -60
y = -326 <<
y = -28
y = -326 <<
y = -2
y = 0
(Status == STOPPED)

layoutY属性在动画过程中随机设置为起始值。此外,当鼠标光标位于菜单上时,onMouseMove不应触发,因为它只是WebView的处理程序。但是,动画完成后,我将光标移动到窗口顶部 3% 下方,vbox_slideview消失,其layoutY立即设置为 -326 。这不应该发生在超过vbox_slideview

为什么vbox_slideview不断被重置到其起始位置?


更新

如果我将光标非常快速地移动到顶部 3% 以上,这样它就不会在那里徘徊,动画就会运行良好。这让我认为事件是并行处理的,而不是顺序处理的,即使第一个阻止后续事件处理,已经有一堆其他事件正在处理。

您向我们展示了滑块的"弹出"部分,自动隐藏部分也需要进行全面检查。我怀疑您的自动隐藏部分在弹出滑动和完成后都会不断被触发。无论如何,为什么每次都创建时间线,只使用它的一个实例。
在我的测试用例(Javafx 版本 2.2.0(上,与您的代码类似,滑块显示时没有闪烁,并在动画完成后以 layoutY = 0 保留在屏幕上:

Sample.fxml

<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<StackPane id="StackPane" minHeight="568.0" minWidth="824.0" xmlns:fx="http://javafx.com/fxml" fx:controller="demo.SampleController">
  <children>
    <WebView fx:id="wv" onMouseMoved="#onMouseMove" prefHeight="568.0" prefWidth="824.0" />
    <VBox fx:id="vbox_slideview" fillWidth="true" maxHeight="326.0" maxWidth="824.0" minHeight="326.0" minWidth="824.0" prefHeight="326.0" prefWidth="824.0"
          visible="false" StackPane.alignment="TOP_CENTER" style="-fx-background-color: green">
      <StackPane.margin>
       <Insets top="-326.0" />
      </StackPane.margin>
    </VBox>
  </children>
</StackPane>

采样控制器

public class SampleController implements Initializable {
    @FXML
    private VBox vbox_slideview;
    private Timeline timeline;
    @FXML
    public void onMouseMove(MouseEvent e) {
        if (e.getSceneY() < 0.03 * JavaFXApplication110.instance.stage.getScene().getHeight()) {
            this.vbox_slideview.setVisible(true);
            if (timeline.getStatus().equals(Animation.Status.STOPPED)) {
                timeline.play();
            }
        }
    }
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        vbox_slideview.layoutYProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2) {
                System.out.println("y = " + arg0.getValue());
            }
        });
        timeline = TimelineBuilder.create().keyFrames(
                new KeyFrame(
                Duration.millis(300),
                new KeyValue(this.vbox_slideview.layoutYProperty(),
                0)))
                .build();
    }
}

不要使用 LayoutX/Y(( ...使用 TranslateX/Y((

相关内容

  • 没有找到相关文章

最新更新