CSS 样式应用于应用栏太晚了



我有一个包含ListViewView。 首次加载视图时,创建列表单元格需要一些时间。为了防止 UI 看起来被阻止,我将调用包装在Platform.runLaterlistView.setItems,并将 listView 的占位符设置为加载过程的指示器。
视图AppBar包含一个TextField和一些Buttons,它们通过css文件设置样式。当按钮的样式正确时,文本字段首先出现时未应用任何样式,即黑色,一旦填充列表视图,文本字段也会应用其样式。

这种延迟的原因可能是什么?

@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>

发布代码后,我可以在 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 文本是黑色的,只有在稍后才会设置样式。

如果将该代码段修改为以下代码段:

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是这样做的良好机制。

最新更新