如果用户将鼠标悬停在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);
}
你会注意到我把动画放在了一个类变量中。这是因为我尝试了其他几种阻止动画的方法,这个问题的帖子建议:How to find out if a transition is already running on a node?所有这些方法都提供相同的结果。
我还在initialize()
:
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%以上,那么它就不会停留在那里,动画运行正常。这使我认为事件是并行处理而不是顺序处理的,即使第一个事件阻止了处理后续事件,也已经有许多其他事件正在处理中。
答案 0 :(得分:1)
您向我们展示了滑块的“弹出”部分,自动隐藏部分也需要进行全面检查。我怀疑你的自动隐藏部分在弹出滑动和完成之后不断被触发。无论如何,为什么每次都要创建时间轴,只使用它的一个实例 在我的测试用例(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>
SampleController
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();
}
}
答案 1 :(得分:0)
不要使用LayoutX / Y()...使用TranslateX / Y()