2017-10-20 178 views
1

我正在嘗試使用自定義HBox CardCells創建卡片。Gluon Mobile Cardpane UI Enhancements:Cardcell Generation/Deletion&Cardpane Styling

問題#1

如何設置這個CardPane的背景是什麼?我希望它是透明的,但它不會從這種灰色改變。我曾嘗試直接向節點添加樣式以及添加自定義樣式表。我也曾嘗試的setBackground方法:

enter image description here

問題#從this SO後採取2

,我是能夠添加動畫細胞產生的,它在向上消失。但是,在隨機卡片插入中,不同的單元會丟失我已經嵌入到該單元中的節點。我不知道這是因爲這些卡的回收概念(基於膠子文檔)還是什麼:

enter image description here

問題3:

我創建的功能,使得用戶可以通過向左滑動來刪除卡片。然而,問題#2出現了同樣的問題,但更大的程度上整個細胞丟失,但仍佔用空間。如果我只有一個單元格並向左滑動,它就會一直工作。但是,當我有多個單元格時(例如,我有3個單元格並刪除第2個單元格),事情就會中斷,單元格的事件處理程序被移除,在一個單元格上向左滑動即可在其下面的單元格上開始動畫,等等。有沒有一種方法可以執行此功能,或者是我最好的辦法就是擺脫CardPane並使用VBox和HBox元素的組合?

private void addToCardPane(CustomCard newCard) { 

    ObservableList<Node> items = cardpane.getItems(); 
    boolean override = false; 

    for (int i = 0; i < cardpane.getItems().size(); i++) { 
     CustomCard box = (CustomCard) items.get(i); 
     if (box.checkEquality(newCard)) { 
      box.increaseNumber(newCard); 
      override = true; 
      break; 
     } 
    } 

    if (override == false) { 
     cardpane.getItems().add(newCard); 
     cardpane.layout(); 
     VirtualFlow vf = (VirtualFlow) cardpane.lookup(".virtual-flow"); 
     Node cell = vf.getCell(cardpane.getItems().size() - 1); 
     cell.setTranslateX(0); 
     cell.setOpacity(1.0); 
     if (!cardpane.lookup(".scroll-bar").isVisible()) { 
      FadeInUpTransition f = new FadeInUpTransition(cell); 
      f.setRate(2); 
      f.play(); 
     } else { 
      PauseTransition p = new PauseTransition(Duration.millis(20)); 
      p.setOnFinished(e -> { 
       vf.getCell(cardpane.getItems().size() - 1).setOpacity(0); 
       vf.show(cardpane.getItems().size() - 1); 
       FadeTransition f = new FadeTransition(); 
       f.setDuration(Duration.seconds(1)); 
       f.setFromValue(0); 
       f.setToValue(1); 
       f.setNode(vf.getCell(cardpane.getItems().size() - 1)); 
       f.setOnFinished(t -> { 
       }); 
       f.play(); 
      }); 
      p.play(); 
     } 
    } 
    initializeDeletionLogic(); 
} 

private void initializeDeletionLogic() { 
    VirtualFlow vf = (VirtualFlow) cardpane.lookup(".virtual-flow"); 
    for (int i = 0; i < cardpane.getItems().size(); i++) { 
     CustomCard card = (CustomCard) cardpane.getItems().get(i); 
     Node cell2 = vf.getCell(i); 
     addRemovalLogicForCell(card, cell2); 
    } 
} 

private static double initX = 0; 
private void addRemovalLogicForCell(OpioidCard card, Node cell) { 
    card.setOnMousePressed(e -> { 
     initX = e.getX(); 
    }); 

    card.setOnMouseDragged(e -> { 
     double current = e.getX(); 
     if (current < initX) { 
      if ((current - initX) < 0 && (current - initX) > -50) { 
       cell.setTranslateX(current - initX); 
      } 
     } 
    }); 

    card.setOnMouseReleased(e -> { 
     double current = e.getX(); 
     double delta = current - initX; 
     System.out.println(delta); 
     if (delta > -50) { 
      int originalMillis = 500; 
      double ratio = (50 - delta)/50; 
      int newMillis = (int) (500 * ratio); 
      TranslateTransition translate = new TranslateTransition(Duration.millis(newMillis)); 
      translate.setToX(0); 
      translate.setNode(cell); 
      translate.play(); 
     } else { 
      FadeTransition ft = new FadeTransition(Duration.millis(300), cell); 
      ft.setFromValue(1.0); 
      ft.setToValue(0); 

      TranslateTransition translateTransition 
        = new TranslateTransition(Duration.millis(300), cell); 
      translateTransition.setFromX(cell.getTranslateX()); 
      translateTransition.setToX(-400); 

      ParallelTransition parallel = new ParallelTransition(); 
      parallel.getChildren().addAll(ft, translateTransition); 
      parallel.setOnFinished(evt -> { 

       removeCard(card); 

       ObservableList<CustomCard > cells = FXCollections.observableArrayList(); 

       for(int i = 0; i < this.cardpane.getItems().size(); i++){ 
        cells.add((CustomCard)this.cardpane.getItems().get(i)); 
       } 

       this.cardpane.getItems().clear(); 
       for(int i = 0; i < cells.size(); i++){ 
        this.cardpane.getItems().add(cells.get(i)); 
       } 

       initializeDeletionLogic(); 
       initX = 0; 
      }); 

      parallel.play(); 
     } 
    }); 
} 

private void removeCard(OpioidCard card) { 
    for (int i = 0; i < cardpane.getItems().size(); i++) { 
     if (cardpane.getItems().get(i) == card) { 
      cardpane.getItems().remove(i); 
      updateNumber(this.totalNumber); 
      break; 
     } 
    } 

    for (int i = 0; i < dataList.size(); i++) { 
     if (dataList.get(i).getName().equalsIgnoreCase(card.getName())) { 
      dataList.remove(i); 
     } 
    } 

    this.cardpane.layout(); 
    initializeDeletionLogic(); 
} 

enter image description here

工作演示ISSUE作者:

package com.mobiletestapp; 

import com.gluonhq.charm.glisten.animation.FadeInUpTransition; 
import com.gluonhq.charm.glisten.control.AppBar; 
import com.gluonhq.charm.glisten.control.CardCell; 
import com.gluonhq.charm.glisten.control.CardPane; 
import com.gluonhq.charm.glisten.mvc.View; 
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon; 
import com.sun.javafx.scene.control.skin.VirtualFlow; 
import javafx.animation.FadeTransition; 
import javafx.animation.ParallelTransition; 
import javafx.animation.PauseTransition; 
import javafx.animation.TranslateTransition; 
import javafx.scene.Node; 
import javafx.scene.control.Label; 
import javafx.scene.layout.StackPane; 
import javafx.util.Duration; 

public class BasicView extends View { 

    class CustomCard extends StackPane{ 
     public CustomCard(String text){ 
      this.getChildren().add(new Label(text)); 
     } 
    } 
    private static double initX = 0; 
    private static void addRemovalLogicForCell(CustomCard card, Node cell) { 
     card.setOnMousePressed(e -> { 
      initX = e.getX(); 
     }); 

     card.setOnMouseDragged(e -> { 
      double current = e.getX(); 
      if (current < initX) { 
       if ((current - initX) < 0 && (current - initX) > -50) { 
        cell.setTranslateX(current - initX); 
       } 
      } 
     }); 

     card.setOnMouseReleased(e -> { 
      double current = e.getX(); 
      double delta = current - initX; 
      System.out.println(delta); 
      if (delta > -50) { 
       int originalMillis = 500; 
       double ratio = (50 - delta)/50; 
       int newMillis = (int) (500 * ratio); 
       TranslateTransition translate = new TranslateTransition(Duration.millis(newMillis)); 
       translate.setToX(0); 
       translate.setNode(cell); 
       translate.play(); 
      } else { 
       FadeTransition ft = new FadeTransition(Duration.millis(300), cell); 
       ft.setFromValue(1.0); 
       ft.setToValue(0); 

       TranslateTransition translateTransition 
         = new TranslateTransition(Duration.millis(300), cell); 
       translateTransition.setFromX(cell.getTranslateX()); 
       translateTransition.setToX(-400); 

       ParallelTransition parallel = new ParallelTransition(); 
       parallel.getChildren().addAll(ft, translateTransition); 
       parallel.setOnFinished(evt -> { 

        for(int i = 0; i < cardPane.getItems().size(); i++){ 
         if(cardPane.getItems().get(i) == card){ 
          cardPane.getItems().remove(i); 
         } 
        } 
        initX = 0; 
       }); 

       parallel.play(); 
      } 
     }); 
    } 

    private static CardPane cardPane = null; 
    public BasicView(String name) { 
     super(name); 

     cardPane = new CardPane(); 

     cardPane.setCellFactory(p -> new CardCell<CustomCard>() { 

      @Override 
      public void updateItem(CustomCard item, boolean empty) { 
       super.updateItem(item, empty); 
       if (!empty) { 
        setText(null); 
        setGraphic(item); 
       } else { 
        setText(null); 
        setGraphic(null); 
       } 
      } 
     }); 



     setCenter(cardPane); 
    } 

    private static void addCard(CustomCard newCard){ 
     cardPane.getItems().add(newCard); 
      cardPane.layout(); 
      VirtualFlow vf = (VirtualFlow) cardPane.lookup(".virtual-flow"); 
      Node cell = vf.getCell(cardPane.getItems().size() - 1); 
      cell.setTranslateX(0); 
      cell.setOpacity(1.0); 
      if (!cardPane.lookup(".scroll-bar").isVisible()) { 
       FadeInUpTransition f = new FadeInUpTransition(cell); 
       f.setRate(2); 
       f.play(); 
      } else { 
       PauseTransition p = new PauseTransition(Duration.millis(20)); 
       p.setOnFinished(e -> { 
        vf.getCell(cardPane.getItems().size() - 1).setOpacity(0); 
        vf.show(cardPane.getItems().size() - 1); 
        FadeTransition f = new FadeTransition(); 
        f.setDuration(Duration.seconds(1)); 
        f.setFromValue(0); 
        f.setToValue(1); 
        f.setNode(vf.getCell(cardPane.getItems().size() - 1)); 
        f.setOnFinished(t -> { 
        }); 
        f.play(); 
       }); 
       p.play(); 
      } 
      addRemovalLogicForCell(newCard, cell); 
    } 

    @Override 
    protected void updateAppBar(AppBar appBar) { 
     appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu"))); 
     appBar.setTitleText("Basic View"); 
     appBar.getActionItems().add(MaterialDesignIcon.ADD.button(e -> addCard(new CustomCard("Hello")))); 
    } 

} 

添加和向左滑動爲刪除時,這導致了以下的輸出:

enter image description here

回答

1

如果您使用ScenicView進行檢查,您會注意到CardPane擁有一個CharmListView控件,該控件使用一個內部的ListView控件,該控件取其父項的大小。

所以這應該工作:

.card-pane > .charm-list-view > .list-view { 
    -fx-background-color: transparent; 
} 

正如我提到的,控制是基於ListView,所以提供細胞的方法是使用電池工廠。正如你可以在控件的JavaDoc中看到的那樣:

CardPane通過重複使用卡爲大量物品做好準備。

開發人員可以通過指定一個細胞工廠通過cellFactoryProperty()個性化細胞創建。默認的單元工廠準備接受來自擴展Node的類或者不從Node擴展的其他類的對象,在後一種情況下,卡文本將由對象的Object.toString()實現給出。

如果你不使用它,可以考慮使用這樣的事情:

cardPane.setCellFactory(p -> new CardCell<T>() { 

    @Override 
    public void updateItem(T item, boolean empty) { 
     super.updateItem(item, empty); 
     if (!empty) { 
      setText(null); 
      setGraphic(createContent(item)); 
     } else { 
      setText(null); 
      setGraphic(null); 
     } 
    } 
}); 

這應該爲您管理卡的佈局,避免空白單元格或他們的錯誤重複使用。

至於動畫,使用它不應該有問題。

對於滑動動畫,Comments2.0 sample提供了一個類似的用例:A ListView其中每個單元格使用SlidingListTile。看看它的實現。

您應該可以在CardPane中重複使用它。

試一試,如果您仍然有問題,請在此處發佈工作示例(或提供鏈接),以便我們可以重現它們。

編輯

基礎上發佈代碼,涉及到工廠電池應該如何設置註釋:

所有的JavaFX控制使用的細胞(如ListViewTableView),也是膠子CardPane,遵循MVC模式:

  • 模型。該控件綁定到一個模型,使用該模型的可觀察項目列表。在示例中,String或任何常規POJO,或者作爲首選的JavaFX bean(具有可觀察屬性)。

因此,在這種情況下,你應該有:

CardPane<String> cardPane = new CardPane<>(); 
  • 查看。該控件有一個方法來設置單元格如何渲染模型cellFactory。該工廠可以定義文本或任何圖形節點,如CustomCard

在這種情況下,你應該有:

cardPane.setCellFactory(p -> new CardCell<String>() { 

     private final CustomCard card; 
     { 
      card = new CustomCard(); 
     } 

     @Override 
     public void updateItem(String item, boolean empty) { 
      super.updateItem(item, empty); 
      if (item != null && !empty) { 
       card.setText(item); 
       setGraphic(card); 
       setText(null); 
      } else { 
       setGraphic(null); 
       setText(null); 
      } 
     } 
    }); 

其中:

class CustomCard extends StackPane { 

    private final Label label; 

    public CustomCard(){ 
     label = new Label(); 
     getChildren().add(label); 
    } 

    public void setText(String text) { 
     label.setText(text); 
    } 
} 

在內部,控制使用管理重用細胞VirtualFlow,只有修改內容(模型)滾動時。

正如您在單元工廠看到的,現在您將迭代模型(字符串),而CustomCard保持不變,並且只更新內容。

使用此方法不會出現您所描述的任何問題,至少在添加單元格時是如此。

EDIT 2

我拿出那對我來說工作正常,應該可以解決所提到的所有問題的解決方案。除了之前提到的之外,還需要恢復在updateItem回調中應用於CustomCard的轉換。

public class BasicView extends View { 

    private final CardPane<String> cardPane; 

    public BasicView(String name) { 
     super(name); 

     cardPane = new CardPane<>(); 

     cardPane.setCellFactory(p -> new CardCell<String>() { 

      private final CustomCard card; 
      private final HBox box; 
      { 
       card = new CustomCard(); 
       card.setMaxWidth(Double.MAX_VALUE); 
       card.prefWidthProperty().bind(widthProperty()); 
       box = new HBox(card); 
       box.setAlignment(Pos.CENTER); 
       box.setStyle("-fx-background-color: grey"); 
       addRemovalLogicForCell(card); 
      } 

      @Override 
      public void updateItem(String item, boolean empty) { 
       super.updateItem(item, empty); 
       if (item != null && !empty) { 
        card.setText(item); 
        card.setTranslateX(0); 
        card.setOpacity(1.0); 
        setGraphic(box); 
        setText(null); 
       } else { 
        setGraphic(null); 
        setText(null); 
       } 
      } 
     }); 

     setCenter(cardPane); 
    } 

    class CustomCard extends StackPane { 

     private final Label label; 

     public CustomCard(){ 
      label = new Label(); 
      label.setStyle("-fx-font-size: 20;"); 
      getChildren().add(label); 
      setStyle("-fx-padding: 20; -fx-background-color: white"); 
      setPrefHeight(100); 
     } 

     public void setText(String text) { 
      label.setText(text); 
     } 

     public String getText() { 
      return label.getText(); 
     } 
    } 

    private double initX = 0; 
    private void addRemovalLogicForCell(CustomCard card) { 
     card.setOnMousePressed(e -> { 
      initX = e.getX(); 
     }); 

     card.setOnMouseDragged(e -> { 
      double current = e.getX(); 
      if ((current - initX) < 0 && (current - initX) > -50) { 
       card.setTranslateX(current - initX); 
      } 
     }); 

     card.setOnMouseReleased(e -> { 
      double current = e.getX(); 
      double delta = current - initX; 
      if (delta < 50) { 
       if (delta > -50) { 
        int originalMillis = 500; 
        double ratio = (50 - delta)/50; 
        int newMillis = (int) (500 * ratio); 
        TranslateTransition translate = new TranslateTransition(Duration.millis(newMillis)); 
        translate.setToX(0); 
        translate.setNode(card); 
        translate.play(); 
       } else { 
        FadeTransition ft = new FadeTransition(Duration.millis(300), card); 
        ft.setFromValue(1.0); 
        ft.setToValue(0); 

        TranslateTransition translateTransition 
          = new TranslateTransition(Duration.millis(300), card); 
        translateTransition.setFromX(card.getTranslateX()); 
        translateTransition.setToX(-400); 

        ParallelTransition parallel = new ParallelTransition(); 
        parallel.getChildren().addAll(ft, translateTransition); 
        parallel.setOnFinished(evt -> { 
         cardPane.getItems().remove(card.getText()); 
         initX = 0; 
        }); 

        parallel.play(); 
       } 
      } 

     }); 
    } 

    private void addCard(String newCard){ 
     cardPane.getItems().add(newCard); 
     cardPane.layout(); 

     VirtualFlow vf = (VirtualFlow) cardPane.lookup(".virtual-flow"); 
     IndexedCell cell = vf.getCell(cardPane.getItems().size() - 1); 
     cell.setTranslateX(0); 
     cell.setOpacity(0); 
     if (! cardPane.lookup(".scroll-bar").isVisible()) { 
      FadeInUpTransition f = new FadeInUpTransition(cell, true); 
      f.setRate(2); 
      f.play(); 
     } else { 
      PauseTransition p = new PauseTransition(Duration.millis(20)); 
      p.setOnFinished(e -> { 
       vf.show(cardPane.getItems().size() - 1); 
       FadeInTransition f = new FadeInTransition(cell); 
       f.setRate(2); 
       f.play(); 
      }); 
      p.play(); 
     } 
    } 

    @Override 
    protected void updateAppBar(AppBar appBar) { 
     appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu"))); 
     appBar.setTitleText("Basic View"); 
     appBar.getActionItems().add(MaterialDesignIcon.ADD.button(e -> addCard("Hello #" + new Random().nextInt(100)))); 
    } 

} 
+0

何塞,我發佈了一個完整的問題演示。讓我知道它是否有幫助。不幸的是,細胞工廠方法似乎不適用於我,除非我實施不正確。您可以看到如果在滾動下方添加一堆框,框中的一些內容會消失。如果您有超過1個單元格並嘗試向左滑動以移除,奇怪的事情就會發生。 –

+0

難道是因爲我隱藏了細胞,然後當CardPane想要回收它們時,它們仍然隱藏着? –

+0

我已經編輯了我的答案,並解釋了你應該如何做細胞工廠。我沒有檢查刪除部分。 –