Vaadin 14 中缺少 GridLayout

问题描述 投票:0回答:2

Vaadin 8 有一个布局,它使用 CSS 网格来布局组件的各个部分Vaadin 网格布局。 借助此布局,您可以拥有一个网格,其中单元格水平和垂直跨越多个列和行。 现在 Vaadin 14 中不再有 GridLayout。 Vaadin 告诉我们,现在 FormLayout 支持多列,在某种程度上它取代了 GridLayout (link)。我认为由于不同的原因,情况并非如此。

  • 从上下文来看,FormLayout 应该在表单上使用。但是如果我们想布局其他组件怎么办?
  • 使用 GridLayout,您可以准确控制要在网格中放置元素的位置。我还没有找到在 FormLayout 中做到这一点的方法
  • 没有办法让元素跨越多行,如 github
  • 上讨论的那样

请随意编辑此问题以向此列表添加更多点。

有什么好的替代方案吗? (除了降级到 vaadin 8,这不是一个真正的替代方案。) 一个明显的解决方案是使用 Polymertemplate 或 Littemplate,但仅使用 Java 的解决方案肯定是首选。 另一种解决方案可能是将布局放入其他布局中以构建看起来像网格布局的布局。但这可能会更难维护。

java vaadin vaadin14
2个回答
4
投票

看看Vaadin组件目录中的Css Grid Layout

有一个演示这里

它支持行和列跨越,例如此示例来自使用 FluentGridLayout.withItemWithSize() 方法的演示:

public class FlexibleGridLayoutExample2 extends HorizontalLayout {
    public FlexibleGridLayoutExample2() {
        FlexibleGridLayout layout = new FlexibleGridLayout()
                .withColumns(Repeat.RepeatMode.AUTO_FILL, new MinMax(new Length("190px"), new Flex(1)))
                .withAutoRows(new Length("190px"))
                .withItems(
                        new ExampleCard(), new ExampleCard())
                .withItemWithSize(new ExampleCard(), 2, 2) // add item with a custom size (2 rows and 2 cols)
                .withItems(
                        new ExampleCard(), new ExampleCard(), new ExampleCard(), new ExampleCard(), new ExampleCard(),
                        new ExampleCard(), new ExampleCard(), new ExampleCard(), new ExampleCard(), new ExampleCard(),
                        new ExampleCard(), new ExampleCard(), new ExampleCard(), new ExampleCard(), new ExampleCard(), 
                        new ExampleCard(), new ExampleCard(), new ExampleCard()
                )
                .withPadding(true)
                .withSpacing(true)
                .withAutoFlow(GridLayoutComponent.AutoFlow.ROW_DENSE) // allow the item order to be changed to let elements fill empty spaces.
                .withOverflow(GridLayoutComponent.Overflow.AUTO);
        layout.setSizeFull();
        setSizeFull();
        add(layout);
    }
}

您还可以使用 FluentGridLayout 指定单元格的开始和结束位置。 withRowAndColumn() 方法:

public class CssGridLayoutExample1 extends VerticalLayout {
    public CssGridLayoutExample1() {
        Component alignTestComponent = new ExampleCard();
        FluentGridLayout layout = new FluentGridLayout()
               .withTemplateRows(new Flex(1), new Flex(1), new Flex(1))
               .withTemplateColumns(new Flex(1), new Flex(1), new Flex(1))
               .withColumnAlign(alignTestComponent, GridLayoutComponent.ColumnAlign.END)
               .withRowAlign(alignTestComponent, GridLayoutComponent.RowAlign.END)
               .withRowAndColumn(alignTestComponent, 1, 1, 1, 3)
               .withRowAndColumn(new ExampleCard(), 2, 1)
               .withRowAndColumn(new ExampleCard(), 2, 2)
               .withRowAndColumn(new ExampleCard(), 1, 3, 3, 3);
        layout.setSizeFull();
        setSizeFull();
        add(layout);
    }
}

0
投票

参加派对太晚了,但你可以使用我的 GridLayout 实现:

   public class DwGridLayout extends Composite<Div> {

    private interface MatrixConsumer {
        void execute(int colIndex, int rowIndex);
    }

    private final static String CSS_CLASS_CELL_POSITION_COL_INDEX_PREFIX = "cell-pos-col-";
    private final static String CSS_CLASS_CELL_POSITION_ROW_INDEX_PREFIX = "cell-pos-row-";
    private final static String CSS_CLASS_CELL_CONTENT_DEFAULT = "cell-content-default";
    private final static String CSS_BORDER_STYLE = "1px solid grey";


    private final int amountOfColumns;
    private final int amountOfRows;
    private boolean displayBorder;
    private Div[][] colRowCellMatrix;

    public DwGridLayout(int amountOfColumns, int amountOfRows) {
        this.amountOfColumns = amountOfColumns;
        this.amountOfRows = amountOfRows;
        this.colRowCellMatrix = new Div[amountOfColumns][amountOfRows];
        this.getContent().getStyle().set("display", "grid");
        this.getContent().getStyle().set("grid-template-columns", "min-content ".repeat(this.amountOfColumns));
        this.getContent().getStyle().set("overflow-x", "auto");
        this.getContent().getStyle().set("width", "100%");

        initCellMatrix();
        reloadGridComposite();
    }

    private void initCellMatrix() {
        iterateOverMatrixAndExecute((colIndex, rowIndex) -> colRowCellMatrix[colIndex][rowIndex] = createCell(colIndex, rowIndex, null));
    }

    private void reloadGridComposite() {
        this.getContent().removeAll();
        iterateOverMatrixAndExecute((colIndex, rowIndex) -> this.getContent().add(colRowCellMatrix[colIndex][rowIndex]));

        if (displayBorder) {
            displayBorder();
        }
    }

    private void displayBorder() {
        for (int rowIndex = 0; rowIndex < amountOfRows; rowIndex++) {
            colRowCellMatrix[0][rowIndex].getStyle().set("border-left", CSS_BORDER_STYLE);
            boolean atLeastOneWrapperHasContent = getComponentWrappersOfRow(rowIndex).stream()
                    .anyMatch(compWrapper -> !compWrapper.getClassNames().contains(CSS_CLASS_CELL_CONTENT_DEFAULT));
            if (atLeastOneWrapperHasContent) {
                for (int columnIndex = 0; columnIndex < amountOfColumns; columnIndex++) {
                    colRowCellMatrix[columnIndex][rowIndex].getStyle().set("border-bottom", CSS_BORDER_STYLE);
                }
            }
        }
        for (int columnIndex = 0; columnIndex < amountOfColumns; columnIndex++) {
            colRowCellMatrix[columnIndex][0].getStyle().set("border-top", CSS_BORDER_STYLE);
            boolean atLeastOneWrapperHasContent = getComponentWrappersOfColumn(columnIndex).stream()
                    .anyMatch(compWrapper -> !compWrapper.getClassNames().contains(CSS_CLASS_CELL_CONTENT_DEFAULT));
            if (atLeastOneWrapperHasContent) {
                for (int rowIndex = 0; rowIndex < amountOfRows; rowIndex++) {
                    colRowCellMatrix[columnIndex][rowIndex].getStyle().set("border-right", CSS_BORDER_STYLE);
                }
            }
        }
    }

    private List<Div> getComponentWrappersOfRow(int rowIndex) {
        List<Div> components = new ArrayList<>();
        for (int i = 0; i < amountOfColumns; i++) {
            components.add(colRowCellMatrix[i][rowIndex]);
        }
        return components;
    }

    private List<Div> getComponentWrappersOfColumn(int columnIndex) {
        List<Div> components = new ArrayList<>();
        //noinspection ManualArrayToCollectionCopy
        for (int i = 0; i < amountOfRows; i++) {
            components.add(colRowCellMatrix[columnIndex][i]);
        }
        return components;
    }

    private void iterateOverMatrixAndExecute(MatrixConsumer matrixConsumer) {
        for (int rowIndex = 0; rowIndex < amountOfRows; rowIndex++) {
            for (int colIndex = 0; colIndex < amountOfColumns; colIndex++) {
                matrixConsumer.execute(colIndex, rowIndex);
            }
        }
    }

    private Div createCell(int columnIndex, int rowIndex, Component componentToInput) {
        Div div = new Div();
        div.getClassNames().add(CSS_CLASS_CELL_POSITION_ROW_INDEX_PREFIX + rowIndex);
        div.getClassNames().add(CSS_CLASS_CELL_POSITION_COL_INDEX_PREFIX + columnIndex);
        if (componentToInput == null) {
            div.getClassNames().add(CSS_CLASS_CELL_CONTENT_DEFAULT);
        } else {
            div.getClassNames().remove(CSS_CLASS_CELL_CONTENT_DEFAULT);
        }
        div.add(componentToInput == null ? new Div() : componentToInput);
        return div;
    }

    private void validateCoordinates(int columnIndex, int rowIndex) {
        if (columnIndex >= amountOfColumns) {
            throw new IllegalArgumentException("ColumnIndex " + columnIndex + " is out of bounds of the grid. The biggest ColumnIndex in grid is: " + amountOfColumns);
        }
        if (rowIndex >= amountOfRows) {
            throw new IllegalArgumentException("RowIndex " + rowIndex + " is out of bounds of the grid. The biggest RowIndex in grid is: " + amountOfRows);
        }
    }

    public Component getComponent(int columnIndex, int rowIndex) {
        validateCoordinates(columnIndex, rowIndex);
        Div componentWrapper = colRowCellMatrix[columnIndex][rowIndex];
        return componentWrapper.getChildren().findFirst().orElseThrow();
    }

    public void addComponent(int columnIndex, int rowIndex, Component newComponent) {
        validateCoordinates(columnIndex, rowIndex);

        Div[][] matrixWithNewComponent = new Div[amountOfColumns][amountOfRows];
        iterateOverMatrixAndExecute((colIndexE, rowIndexE) -> matrixWithNewComponent[colIndexE][rowIndexE] =
                (colIndexE == columnIndex && rowIndexE == rowIndex)
                        ? createCell(colIndexE, rowIndexE, newComponent)
                        : colRowCellMatrix[colIndexE][rowIndexE]);
        colRowCellMatrix = matrixWithNewComponent;
        reloadGridComposite();
    }

    public void setId(String id) {
        this.getContent().setId(id);
    }

    public void setDisplayBorder(boolean displayBorder) {
        this.displayBorder = displayBorder;
    }

    /**
     * <b style="color: red;">Beware: Adding a new Component to a position with a tooltip will remove the tooltip.</b>
     */
    public void addTooltipForComponent(int columnIndex, int rowIndex, String tooltip) {
        colRowCellMatrix[columnIndex][rowIndex].setTitle(tooltip);
        reloadGridComposite();
    }

    @SuppressWarnings("unused")
    private Label createDebugCell(int colIndex, int rowIndex) {
        return new Label(colIndex + ":" + rowIndex);
    }

}

  
© www.soinside.com 2019 - 2024. All rights reserved.