问题
你好,
我正在尝试编写一个应用程序,在其中每个新的ListView条目都会得到动画效果。以下是我的代码:
public class BookCell extends ListCell<Book>
{
private Text text;
private HBox h;
public BookCell()
{
this.text = new Text();
this.h = new HBox();
this.h.getChildren().add(text);
super.getStyleClass().add("book-list-cell");
super.itemProperty().addListener((obs,oldv,newv)->{
if(newv != null )
{
if(getIndex() == this.getListView().getItems().size()-1 )
{
//why does this get called twice for each update?
System.out.println("isbn = "+newv.getIsbn().get() + " lastIndexOf=" + this.getListView().getItems().lastIndexOf(newv)+" Index="+getIndex()+" size="+this.getListView().getItems().size());
runAnimation();
}
}
});
this.getChildren().add(h);
}
@Override
protected void updateItem(Book item, boolean empty)
{
super.updateItem(item, empty);
if(!empty)
super.setGraphic(h);
text.setText(item == null ? "" : item.getIsbn().get());
}
public void runAnimation()
{
FadeTransition f = new FadeTransition();
f.setFromValue(0);
f.setToValue(1);
f.setNode(this);
f.play();
}
}
我试图将监听器添加到itemProperty中,但我得到了一些奇怪的行为。首先,每次我添加一个条目时,监听器都会触发两次:
这导致动画播放两次。即使在这种情况下几乎不会注意到,但这可能有点尴尬。
此外,在列表开始滚动后,有时会为可见条目重复执行动画:
老实说,如果一个项目再次变得可见,我并不一定介意重复动画,但现在的情况非常不可靠,哪些单元格会被动画化还很难确定。
我知道单元格是虚拟控制的,在一段时间内会被重用。但我很难找到一种可靠的方法来确定屏幕上是否出现了非空单元格。
问题
- 为什么监听器会触发两次?
- 观察屏幕上单元格的出现/消失的最佳方法是什么?
- 有更好的方法向ListView添加动画吗?
完整代码
这可能会有所帮助,因此这是我的css和main文件。
Main.java
public class Main extends Application
{
static int newBookIndex = 1;
public static final ObservableList<Book> data = FXCollections.observableArrayList();
@Override
public void start(Stage primaryStage)
{
try
{
GridPane myPane = (GridPane)FXMLLoader.load(getClass().getResource("quotes.fxml"));
ListView<Book> lv = (ListView<Book>) myPane.getChildren().get(0);
Button addButton = (Button) myPane.getChildren().get(1);
addButton.setText("Add Book");
addButton.setOnAction((event)->{
data.add(new Book(String.valueOf(newBookIndex++),"test"));
});
lv.setEditable(true);
data.addAll(
new Book("123","Hugo"),
new Book("456","Harry Potter")
);
lv.setItems(data);
lv.setCellFactory((param)->return new BookCell());
Scene myScene = new Scene(myPane);
myScene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(myScene);
primaryStage.show();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
}
application.css (基于 https://github.com/privatejava/javafx-listview-animation)
应用程序css文件(基于 https://github.com/privatejava/javafx-listview-animation)
.book-list-cell:odd{
-fx-background-image: url('./wooden2.png') ,url('./gloss.png');
-fx-background-repeat: repeat,no-repeat;
}
.book-list-cell:empty {
-fx-background-image: url('./gloss.png');
-fx-background-repeat: repeat;
}
.book-list-cell {
-fx-font-size:45px;
-fx-font-family: 'Segoe Script';
}
.book-list-cell:selected,.book-list-cell:selected:hover{
-fx-border-color:linear-gradient(to bottom,transparent,rgb(22,22,22,1));
-fx-border-width:2 2 2 10px;
-fx-effect:innershadow( three-pass-box,#764b0c,30,0.3,0,0);
}
.book-list-cell:hover{
-fx-border-color:rgb(255,255,255,0.7);
-fx-border-width:1 1 1 10px;
}
.book-list-cell{
-fx-background-image: url('./wooden.png') ,url('./gloss.png');
-fx-background-repeat: repeat,no-repeat;
-fx-background-position:left top;
-fx-background-size: auto,100% 40%;
}