我目前正在使用GluonHQ和JavaFXPorts开发使用JavaFX的移动应用程序。我的一个屏幕包含一个列表视图,您可以从下面的屏幕截图中看到,这是从我的iPhone 6中获取的。
我注意到移动设备中滚动条存在以下问题:
任何人都可以帮我解决这些问题。如何定义滚动条再次隐藏之前出现的时间?
您可以通过创建ListView并使用某些项加载它来体验这种情况。
感谢Jose Pereda的回答,我已成功克服了上述所有三个问题。这是我用来达到预期结果的代码。 Watch this short video快速了解新滚动条的显示方式和行为方式。再次,何塞,你是老板!请继续提出任何改进意见。
public class ScrollBarView {
public static void changeView(ListView<?> listView) {
listView.skinProperty().addListener(new ChangeListener<Object>() {
private StackPane thumb;
private ScrollBar scrollBar;
boolean touchReleased = true, inertia = false;
@Override
public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
scrollBar = (ScrollBar) listView.lookup(".scroll-bar");
// "hide" thumb as soon as the scroll ends
listView.setOnScrollFinished(e -> {
if (thumb != null) {
touchReleased = true;
playAnimation();
} // if
});
// Fix for 1. When user touches first time, the bar is set invisible so that user cannot see it is
// placed in the wrong position.
listView.setOnTouchPressed(e -> {
if (thumb == null) {
thumb = (StackPane) scrollBar.lookup(".thumb");
thumb.setOpacity(0);
initHideBarAnimation();
} // if
});
// Try to play animation whenever an inertia scroll takes place
listView.addEventFilter(ScrollEvent.SCROLL, e -> {
inertia = e.isInertia();
playAnimation();
});
// As soon as the scrolling starts the thumb become visible.
listView.setOnScrollStarted(e -> {
sbTouchTimeline.stop();
thumb.setOpacity(1);
touchReleased = false;
});
} // changed
private Timeline sbTouchTimeline;
private KeyFrame sbTouchKF1, sbTouchKF2;
// Initialize the animation that hides the thumb when no scrolling takes place.
private void initHideBarAnimation() {
if (sbTouchTimeline == null) {
sbTouchTimeline = new Timeline();
sbTouchKF1 = new KeyFrame(Duration.millis(50), new KeyValue(thumb.opacityProperty(), 1));
sbTouchKF2 = new KeyFrame(Duration.millis(200), (e) -> inertia = false, new KeyValue(thumb.opacityProperty(), 0));
sbTouchTimeline.getKeyFrames().addAll(sbTouchKF1, sbTouchKF2);
} // if
} // initHideBarAnimation
// Play animation whenever touch is released, and when an inertia scroll is running but thumb reached its bounds.
private void playAnimation() {
if(touchReleased)
if(!inertia || (scrollBar.getValue() != 0.0 && scrollBar.getValue() != 1))
sbTouchTimeline.playFromStart();
} // playAnimation()
});
} // changeView
} // ScrollBarView
答案 0 :(得分:1)
如评论中所述,第一个问题是已知的,目前尚未修复。这个问题似乎与滚动条的初始宽度(桌面上20像素)有关,然后设置为8像素(如启用触摸的设备),并移动到其最终位置,此可见的12像素移位到右边。
对于第二个和第三个问题,如果您不想自己修补和构建JDK,则可以覆盖默认行为,因为ScrollBar
控件是VirtualFlow
的一部分控制ListView,两者都可以在运行时通过查找找到。
拥有控件后,您可以根据需要使用其可见性。此属性的唯一问题是它已经从layoutChildren
方法绑定并不断调用。
这是一个非常糟糕的解决方案,但它适用于2)和3):
public class BasicView extends View {
private final ListView<String> listView;
private ScrollBar scrollbar;
private StackPane thumb;
public BasicView(String name) {
super(name);
listView = new ListView<>();
// add your items
final InvalidationListener skinListener = new InvalidationListener() {
@Override
public void invalidated(Observable observable) {
if (listView.getSkin() != null) {
listView.skinProperty().removeListener(this);
scrollbar = (ScrollBar) listView.lookup(".scroll-bar");
listView.setOnScrollFinished(e -> {
if (thumb != null) {
// "hide" thumb as soon as scroll/drag ends
thumb.setStyle("-fx-background-color: transparent;");
}
});
listView.setOnScrollStarted(e -> {
if (thumb == null) {
thumb = (StackPane) scrollbar.lookup(".thumb");
}
if (thumb != null) {
// "show" thumb again only when scroll/drag starts
thumb.setStyle("-fx-background-color: #898989;");
}
});
}
}
};
listView.skinProperty().addListener(skinListener);
setCenter(listView);
}
}