Location>code7788 >text

Qml waterfall layout

Popularity:405 ℃/2024-09-10 18:50:05

[Writing in front]

Recently in the brush nuggets when I saw an article on the layout of the waterfall, but the goose is their implementation of the front-end of the set, I thought Qml there is no similar implementation.

The result of a circle of Baidu also did not ( T_T Qml cool cool cool ), so I in accordance with their own understanding, a simple implementation of a Qml version of the waterfall layout.

About the waterfall stream:

Waterfall Layout, also known as Waterfall Layout or Multi-column Adaptive Layout, is a web layout technique that allows content to be displayed in multiple columns, similar to a waterfall flowing from top to bottom. This layout is particularly suitable for displaying images or card-based content such as photo galleries, news summaries, product listings, etc.

Features of the waterfall layout include:

  1. multicolumn display: The content is split into multiple columns, each of which can be scrolled independently, allowing the page to display more information.
  2. Dynamic width: The width of each column is usually fixed, while the width of content blocks (such as images or cards) can be dynamic to accommodate different screen sizes.
  3. unequal: Content blocks can have different heights, which makes the layout look more natural and attractive.
  4. responsive: The layout automatically adjusts to the user's screen size to provide an optimal viewing experience.
  5. dexterity: Content blocks can flow freely between columns without strict alignment.

[Text Begins]

A classic waterfall layout comes from Little Red Book:

image

And the Qml version of our implementation is shown below:

image

Now on to the ideas:

First consider the width of the screen, vertical screen two columns, horizontal screen can be three or more columns, should be dynamically changed according to the width, then you can calculate the column width:

width: ( - ) /

Therefore, the only thing that is actually unknown is the height of the card:

image

The height of the card consists of three parts as shown:[Height of cover image] + [Height of title] + [Height of card information]

height: coverRealHeight + titleHeight + infoHeight

Now that you have the width and height, the next step is to just calculate thePosition (x, y) Ready to go:

    if ( == ) {
         = 0;
         = 0;
        for (let i = 0; i < ; i++) {
            [i] += [i];
        }
    }

    x = ;
    y = [];

    [] = (height + );

    print(, , , );

     += coverRealWidth + ;

    ++;

    let max = 0;
    for (let j = 0; j < ; j++) {
        max = ([j] + [j]);
    }

     = max;
    

The idea of calculating the x-coordinate is to increase the width of the cards one by one from left to right, and then set it to zero when you reach the last card in the row.

The idea of calculating the y-coordinate is to record an array of the heights of the cards in the lineprevHeight[column]When the last card in the row is reached, an array of y-coordinates of the next card is computed.currentY[column]and the first line is 0.

Up to this point.Rect (x, y, width, height) All are known, and we can directly utilize theRepeater Easily instantiated:

Repeater {
    id: repeater
    model: ListModel {
        id: listModel
        : {
            ();
        }
    }
    delegate: Rectangle {
        id: rootItem
        width: ( - ) /
        height: coverRealHeight + titleHeight + infoHeight
        radius: 4
        clip: true

        property real aspectRatio: coverWidth / coverHeight
        property real coverRealWidth: width
        property real coverRealHeight: width / aspectRatio
        property real titleWidth: width
        property real titleHeight:
        property real infoWidth: width
        property real infoHeight: 50

        : {
            if ( == ) {
                 = 0;
                 = 0;
                for (let i = 0; i < ; i++) {
                    [i] += [i];
                }
            }

            x = ;
            y = [];

            [] = (height + );

            print(, , , );

             += coverRealWidth + ;

            ++;

            let max = 0;
            for (let j = 0; j < ; j++) {
                max = ([j] + [j]);
            }

             = max;
        }

        Column {
            Item {
                id: coverPort
                width: coverRealWidth
                height: coverRealHeight

                Image {
                    : parent
                    :
                    source: cover
                }
            }

            Item {
                id: titlePort
                width: titleWidth
                height:

                Text {
                    id: titleText
                    width:
                    wrapMode:
                    text: title
                    : "Microsoft Black and White (computer science)"
                    : 14
                }
            }

            Item {
                id: infoPort
                width: infoWidth
                height: infoHeight

                RowLayout {
                    : parent

                    CircularImage {
                        id: head
                        : - 5
                        : - 5
                        : 5
                        :
                        source: "file:/C:/Users/mps95/Desktop/"
                    }

                    Text {
                        : true
                        : true
                        text: "subscribers" + user
                        : 14
                        verticalAlignment:
                        elide:
                    }

                    Text {
                        : 100
                        :
                        : 5
                        text: (like ? "🩷" : "🤍") + " " + (() * 1000)
                        : 14
                        horizontalAlignment:
                        verticalAlignment:
                        property int like: (())
                    }
                }
            }
        }
    }
}

loadMore() is to request more card data from the backend, this part needs to be transformed according to the actual needs, I simply generate some simulated data here:

function loadMore() {
    //This part is requested from the backend and must know the cover width and height.
    let titleList = [
            "One line title: Test Test Test Test Test Test",
            "Two line title: test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test",
            
        ];
    for (let i = 0; i < 10; i++) {
        let userId = (() * 100000); let type = (()); {
        let type = (()); //0 image / 1 video
        let cover = "file:/C:/Users/mps95/Desktop/Materials/Anime Pictures/img2" + i + ".jpg"; //cover, both video and image are required
        let url = cover.
        if (type == 1) {
            //url = "file:/test.mp4"; }
        }

        let object = {
            type: type, cover: cover, } let object = {
            cover: cover, user: userId,
            user: userId,
            cover: cover, user: userId, url: url, title: titleList[(( * 2)], titleList[((() * 2)], titleList[() * 2)
            title: titleList[(() * 2)],
            coverWidth: 300, coverHeight: (type + 2) * 100 + (() * 2)
            coverHeight: (type + 2) * 100 + (() * 3) * 80
        }.

        (object).
        (object); (object).
    }
}

[Conclusion]

And finally: project link (more star yah...). ⭐_⭐):

Github'sWaterfallFlow waterfall view (and can be adaptive), similar to Little Red Book

Attention: Images for testing are not included, please change to your own test set.