ios - JavaFXPorts - 移动设备上的滚动条问题

标签 ios scrollbar gluon javafxports gluon-mobile

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

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

  1. 我第一次触摸屏幕时,滚动条出现了一点偏移,然后移动到正确的正确位置。这只是第一次发生很快。 (截图)
  2. 我注意到滚动条会在我每次触摸屏幕时出现,而不仅仅是在我触摸和拖动时出现。在 native iOS 应用程序上,滚动条仅在您触摸和拖动时出现。如果您将手指放在屏幕上然后将其移开,则不会出现滚动条。
  3. 当我从屏幕上移开手指时,滚动条总是需要一些时间才能消失,而在 native 应用程序中它会立即消失。

谁能帮我解决这些问题。如何定义滚动条再次隐藏之前出现的时间?

您可以通过创建一个 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

最佳答案

如评论中所述,第一个问题是已知的,目前尚未修复。问题似乎与滚动条的初始宽度(在桌面中为 20 像素)有关,然后设置为 8 像素(在支持触摸的设备中),并移动到其最终位置,此可见偏移为 12 像素权利。

至于第二个和第三个问题,如果你不想自己打补丁和构建JDK,可以覆盖默认行为,如ScrollBar控件是 VirtualFlow 的一部分ListView 的控件,两者都可以在运行时通过查找找到。

获得控件后,您可以根据需要调整其可见性。此属性的唯一问题是它已经绑定(bind)并不断从 layoutChildren 调用方法。

这是一个非常 hacky 的解决方案,但它适用于 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);
    }

}

关于ios - JavaFXPorts - 移动设备上的滚动条问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41202844/

相关文章:

reactjs - 如何在react-virtualized(CodeSandBox)中向表格添加水平滚动条

android - 如何更改 Gluon Mobile 项目中的 applicationId

ios - 删除以编程方式添加的约束

wpf - RichTextBox 在不可见时滚动到结束不起作用

ios - AppDelegate.swift 中没有这样的模块 'Capacitor'

c# - 在 WPF 中使 TabControl header 可滚动

android - 黑屏启动android

java - 如何在 JavaFX 中正确地将对话框放入动画计时器中

iphone - 如何在安装应用程序时删除推送通知标志

ios - 添加到 super View 的 View 在导航 TableView 时消失