【问题标题】:css style is applied to AppBar too latecss 样式应用于 AppBar 为时已晚
【发布时间】:2017-06-28 06:37:51
【问题描述】:

我有一个View,其中包含一个ListView。 第一次加载视图时,创建 ListCells 需要一些时间。为了防止 UI 看起来被阻塞,我将对 listView.setItems 的调用封装在 Platform.runLater 中,并为 listView 设置一个 placeHolder 作为加载过程的指示器。
视图AppBar 包含一个TextField 和一些Buttons,它们通过css 文件设置样式。虽然按钮样式正确,但 textField 首先出现时没有应用任何样式,即黑色,一旦填充 ListView,TextField 也会应用其样式。

延迟的原因是什么?

    @Override
    protected void onShowing() {
        appBar.setNavIcon(getBackButton());
        appBar.setTitle(searchField.getTextField());
        appBar.getActionItems().addAll(btnSort, btnFilter, moreMenu);
    }

    @Override
    protected void onShown() {
        setItems();
    }

    protected void setItems() {
        if (!firstShow) {
            lview.setItems(items);

        } else {
            if (!items.isEmpty()) {
                lview.setPlaceholder(new Label("loading data..."));
                Platform.runLater(() -> lview.setItems(items));
            }
            firstShow = false;
        }
    }

编辑:

只有 -fx-text-fill 在延迟后应用。所有其他样式都会立即应用。

.app-bar > .title-box > .text-field{ 
    -fx-border-width: 0.0; 
    -fx-border-insets: 0.0;
    -fx-padding: 0.0;
    -fx-font-family: 'Roboto Medium';
    -fx-font-size: 20.0;
    -fx-text-fill: -app-bar-item-color;
    -fx-prompt-text-fill: #59819C;
}

.app-bar > .action-items .button{
    -fx-text-fill: red;
}

重现问题的代码:

public class AppBarTestApp extends MobileApplication {

    private static final String ITEMS_VIEW = "items";

    @Override
    public void init() throws Exception {

        addViewFactory(HOME_VIEW, () ->
            {
                Button btnShowNextView = new Button("Show items view");
                btnShowNextView.setOnAction(e -> switchView(ITEMS_VIEW));

                return new View(HOME_VIEW, new StackPane(btnShowNextView));
            });

        addViewFactory(ITEMS_VIEW, this::loadItemsView);
    }

    @Override
    public void postInit(Scene scene) {
        scene.getStylesheets().add(getClass().getResource("/com/jns/appbartest/view/common.css").toExternalForm());
    }

    private View loadItemsView() {
        URL resource = ItemsPresenter.class.getResource("items.fxml");
        FXMLLoader fxmlLoader = new FXMLLoader(resource);

        try {
            fxmlLoader.load();

        } catch (IOException e) {
            e.printStackTrace();
        }

        return fxmlLoader.getRoot();
    }
}



public class ItemsPresenter {

    private static final MobileApplication app       = MobileApplication.getInstance();

    @FXML
    private View                           view;

    @FXML
    private ListView<String>               lview;

    private Button                         btnBack;
    private Button                         btnMoreMenu;
    private TextField                      txtSearch;

    private boolean                        firstShow = true;

    private ObservableList<String>         items = createItems();

    @FXML
    protected void initialize() {
        view.setOnShowing(e -> onShowing());
        view.setOnShown(e -> onShown());

        btnBack = MaterialDesignIcon.ARROW_BACK.button(e -> app.goHome());
        btnMoreMenu = MaterialDesignIcon.MORE_VERT.button();
        txtSearch = new TextField("Items");
        txtSearch.setPromptText("search");

        lview.setPlaceholder(new Label("no data to display"));
    }

    private void onShowing() {
        app.getAppBar().setNavIcon(btnBack);
        app.getAppBar().setTitle(txtSearch);
        app.getAppBar().getActionItems().add(btnMoreMenu);
    }

    private void onShown() {
        if (!firstShow) {
            lview.setItems(items);

        } else {
            firstShow = false;
            lview.setPlaceholder(new Label("loading data..."));

            Platform.runLater(() -> {
                try {
                    Thread.sleep(2000);  //to simulate a long lasting initial creation of listCells
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                lview.setItems(items);
            });
        }
    }

    private ObservableList<String> createItems() {
        ObservableList<String> items = FXCollections.observableArrayList();
        String name = "Person #";

        for (int i = 0; i < 20; i++) {
            items.add(name + i);
        }

        return items;
    }
}


<View fx:id="view" id="itemsView" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="com.jns.appbartest.view.ItemsPresenter">
    <center>
        <MobileLayoutPane fx:id="pneListView">
            <center>
                <ListView fx:id="lview" />
            </center>
        </MobileLayoutPane>
    </center>
</View>

【问题讨论】:

  • 我无法重现您的问题。我用 ListView 创建了一个简单的测试,我可以在项目显示之前看到文本字段文本或提示文本样式正确。
  • 我已经添加了重现问题的代码

标签: gluon gluon-mobile


【解决方案1】:

通过发布代码,我可以在 Android 上重现该问题。

显然,我参加了这一部分:

private void onShown() {
    lview.setPlaceholder(new Label("loading data..."));
    Platform.runLater(() -> {
        try {
            Thread.sleep(2000);  //to simulate a long lasting initial creation of listCells
        } catch (InterruptedException e) { }
        lview.setItems(items);
    });
}

被添加以模拟单元格的初始创建。

但它准确地显示了您面临的问题:模拟示例显示在 JavaFX 线程 (Platform.runLater) 上,您正在阻止它 (Thread.sleep(2000))。在那段时间里,textField 文本是黑色的,只是后来才被设置样式。

如果你把那个sn-p修改成这个:

private void onShown() {
    lview.setPlaceholder(new Label("loading data..."));
    new Thread(new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            try {
                Thread.sleep(2000);  //to simulate a long lasting initial creation of listCells
            } catch (InterruptedException e) { }
            return null;
        }

        @Override
        protected void succeeded() {
            lview.setItems(items);
        }
    }).start();
}

现在繁重的任务在 JavaFX 线程之外,您可以看到 textField 立即设置样式。

回到你真正的问题:这里的教训可能是你应该把每一个繁重的任务移出 JavaFX 线程,并且只在最后一刻调用它。 Task 是一个很好的机制。

【讨论】:

  • 在我的应用程序中,我从缓存中检索项目,该缓存在应用程序启动时初始化,同时显示预加载器。当 ListCells 被创建时,UI 似乎被阻塞了一段时间。我可以通过为其设置一个 fixedCellSize 来提高最初填充 ListView 的速度,但是仍然存在明显的延迟。即使是模拟示例,按钮怎么可能应用了 css,而 TextField 是稍后设置样式的?
  • 如果你在桌面上运行它,你甚至在 AppBar 上都看不到任何节点,所以 UI 完全冻结了。这就是预期的结果。在 Android 上,开始阻塞 UI 似乎需要更多时间,并且在很短的时间内,节点被添加并部分设置样式。考虑到这一点,如果您可以再延迟一点单元格的创建,您将正确渲染视图,尽管完成其完全加载需要更多时间。
  • 如果我在桌面上运行它,一切看起来都很好。 AppBar 显示所有节点,并具有适当的样式。为了进行快速测试,我使用了 PauseTransition 来延迟单元格的创建,从而解决了这个问题。谢谢何塞。我只是想知道延迟的正确持续时间是多少?
  • 我在 AppBar 节点的fillProperty 中添加了一个Listener,这证实了您在评论中所说的内容。节点是部分样式化的,直到设置了 listView 项,这会中断其余 AppBar 节点的样式化。作为一种解决方法,我在第一次显示视图之前将 Presenters 初始化方法中的 AppBar 节点添加到丢弃的场景,并调用 applyCss。
猜你喜欢
  • 1970-01-01
  • 2016-12-06
  • 2022-10-01
  • 2021-06-05
  • 1970-01-01
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 2019-12-05
相关资源
最近更新 更多