2017-04-20 147 views
0

我試圖動畫ListCell時,他們出現。 特別地,我嘗試在剛剛添加到列表中時爲新單元格創建動畫。 現在它工作得很好,除非我滾動ListView,然後索引變得混亂,錯誤的單元格動畫。 我在項目模型中使用布爾標誌(輸入)來檢測單元格何時用於全新項目。JavaFX自定義ListCell

public class TimeListCell extends ListCell<MarkItem> { 

    private static final String BUTTON_GOTO_MARK_CLASS = "but-markgoto"; 
    private static final String LABEL_TIME_MARK_CLASS = "track-time"; 
    private static final String BUTTON_DELETE_MARK_CLASS = "but-markdel"; 
    private static final String MARK_HIGHLIGHT_CURRENT_CLASS = "highlighted"; 

    private Instant time; 

    private MarkItem markItem; 

    protected ListCellAnimation anim; 

    private HBox root = new HBox(); 
    private Button go = new Button(); 
    private Label track = new Label();; 
    private Button del = new Button(); 

    private ChangeListener<? super Boolean> highlightChange = (e, o, n) -> { setHighlighted(n); }; 

    public TimeListCell (Consumer<MarkItem> onGoto, Consumer<MarkItem> onDelete) { 

     root.setAlignment(Pos.CENTER); 

     go.getStyleClass().add(BUTTON_GOTO_MARK_CLASS); 
     go.setOnAction(e -> { 
      if (onGoto != null) { 
       // Trigger GOTO consumer function 
       onGoto.accept(markItem); 
      } 
     }); 
     track.getStyleClass().add(LABEL_TIME_MARK_CLASS); 
     del.getStyleClass().add(BUTTON_DELETE_MARK_CLASS); 
     del.setOnAction(e -> { 
      // First trigger exit animation then delete item 
      this.animateExit(onDelete); 
     }); 

     root.getChildren().add(go); 
     root.getChildren().add(track); 
     root.getChildren().add(del); 

    } 

    @Override 
    protected void updateItem (final MarkItem item, boolean empty) { 

     super.updateItem(item, empty); 

     if (markItem != null) { 
      markItem.highlightedProperty().removeListener(highlightChange); 
     } 

     if (!empty && item != null) { 
      markItem = item; 
      time = item.getTime(); 

      track.setText(DateUtil.format(time, DateUtil.Pattern.TIME)); 
      setGraphic(root); 

      item.highlightedProperty().addListener(highlightChange); 
      setHighlighted(item.isHighlighted()); 

      if (anim == null) { 
       //Adding Animation to the ListCell 
       anim = new ListCellAnimation(this); 
       //KeyFrame[] f = getKeyFrames(types); 
       KeyFrame[] frames = null; 
       if (anim.getKeyFrames().size() == 0) { 
        KeyFrame[] f = anim.getPopIn(frames); 
        if (f != null) { 
         anim.getKeyFrames().addAll(f); 
        } 
       } 
      } 

      if (item.isEntering()) { 
       //Checking when to play Animation 
       animateEnter(); 
       item.setEntering(false); 
      } 
     } else { 
      setGraphic(null); 
     } 
    } 

    /** 
    * Set/unset cell highlighted style for display. 
    * 
    * @param highlighted 
    *    Whether or not to highlight the cell 
    */ 
    public void setHighlighted (boolean highlighted) { 

     track.getStyleClass().remove(MARK_HIGHLIGHT_CURRENT_CLASS); 
     if (highlighted) 
      track.getStyleClass().add(MARK_HIGHLIGHT_CURRENT_CLASS); 
    } 

    /** 
    * Animate entering cell. 
    */ 
    private void animateEnter() { 
      if (anim != null && anim.getKeyFrames().size() >= 0 
        && (anim.getTimeline().getStatus() == Timeline.Status.STOPPED 
        || anim.getTimeline().getStatus() == Timeline.Status.PAUSED)) { 
        anim.getTimeline().playFromStart(); 
      } 
    } 

    /** 
    * Animate exiting cell. 
    * Trigger DELETE consumer function when animation is complete. 
    */ 
    private void animateExit (Consumer<MarkItem> onDelete) { 

     anim.getReversedTimeline().setOnFinished(t -> { 
      // Remove item from list 
      if (onDelete != null) { 
       onDelete.accept(markItem); 
      } 
      // Prepare cell for next item to use it 
      scaleXProperty().set(1); 
      scaleYProperty().set(1); 
      }); 
     anim.getReversedTimeline().playFromStart(); 
    } 

    public Instant getTime() { 

     return time; 
    } 
} 

有沒有人有任何想法會弄亂單元格索引? 謝謝。

回答

0

如果這是動畫再次用來顯示不是「進入」的項目一個單元格,然後你需要停止當前的動畫:

if (item.isEntering()) { 
     //Checking when to play Animation 
     animateEnter(); 
     item.setEntering(false); 
    } else { 
     anim.getTimeline().stop(); 
    } 

在一般情況下,你似乎是假設任何給定單元格只用於單個項目,當然不是這種情況。代碼中可能存在其他錯誤,這是此假設的後果,但這是我能看到的主要錯誤。

+0

感謝James的幫助。 – keuluu

+0

再次感謝詹姆斯。但是停止動畫並沒有什麼好處,因爲updateItem被每次「刷新」調用幾次。項目在後續調用中不再「輸入」,因此動畫停止。事實上,除了項目列表很長並且我開始滾動它之外,它現在的工作方式正常。當我滾動並在列表末尾創建一個或多個新單元格時(我知道單元格被重新分配給可見項目),那麼當我在列表中添加一個新項目時,動畫將發生在錯誤的單元格上,儘管高亮操作目標正確的單元格... – keuluu

+0

任何滾動之前一切正常。但是當我向下滾動並顯示單元格時(例如2個單元格),那麼當我創建一個新項目時,動畫單元格將與代表創建項目的單元格相距2個單元格。 – keuluu