2017-10-20 177 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

我已经编辑了我的答案,并解释了你应该如何做细胞工厂。我没有检查删除部分。 –