JavaFXPorts - 移动设备上的ScrollBar问题

时间:2016-12-17 20:41:12

标签: ios scrollbar gluon javafxports gluon-mobile

我目前正在使用GluonHQ和JavaFXPorts开发使用JavaFX的移动应用程序。我的一个屏幕包含一个列表视图,您可以从下面的屏幕截图中看到,这是从我的iPhone 6中获取的。

我注意到移动设备中滚动条存在以下问题:

  1. 第一次触摸屏幕时,滚动条显示有点偏离位置,然后移动到正确的正确位置。这只是第一次发生。 (截图)
  2. 我注意到每次触摸屏幕时都会出现滚动条,而不仅仅是在我触摸和拖动时。在本机iOS应用程序上,只有在您触摸并拖动时才会显示滚动条。如果您将手指放在屏幕上然后将其移除,则不会出现滚动条。
  3. 当我从屏幕上移开手指时,滚动条总是需要一些时间才会消失,而在原生应用中,它会立即消失。
  4. 任何人都可以帮我解决这些问题。如何定义滚动条再次隐藏之前出现的时间?

    您可以通过创建ListView并使用某些项加载它来体验这种情况。

    enter image description here

    更新

    感谢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
    

1 个答案:

答案 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);
    }

}