Qml 实现瀑布流布局

news/2024/9/19 15:44:19/文章来源:https://www.cnblogs.com/mengps/p/18406941

【写在前面】

最近在刷掘金的时候看到一篇关于瀑布流布局的文章,然鹅他们的实现都是前端的那套,就想着 Qml 有没有类似实现。

结果百度了一圈也没有( T_T Qml 凉了凉了 ),于是,我按照自己理解,简单实现了一个 Qml 版的瀑布流布局。

关于瀑布流:

瀑布流布局(Waterfall Layout),也被称为瀑布式布局或多栏自适应布局,是一种网页布局技术,它允许内容以多列的形式显示,类似于瀑布一样从上到下流动。这种布局方式特别适合于展示图片或卡片式内容,如图片库、新闻摘要、商品列表等。

瀑布流布局的特点包括:

  1. 多列显示:内容被分割成多列,每列可以独立滚动,使得页面可以展示更多的信息。
  2. 动态宽度:每列的宽度通常是固定的,而内容块(如图片或卡片)的宽度可以是动态的,以适应不同的屏幕大小。
  3. 不等高:内容块的高度可以不同,这样可以使布局看起来更加自然和有吸引力。
  4. 响应式:布局可以根据用户的屏幕尺寸自动调整,以提供最佳的浏览体验。
  5. 灵活性:内容块可以自由地在列之间流动,不需要严格的对齐。

【正文开始】

一个经典的瀑布流布局来自小红书:

image

而我们实现的 Qml 版效果图如下:

image

现在开始讲解思路:

首先考虑屏幕宽度,竖屏两列,横屏可以三列或者更多,应当根据宽度动态改变,然后便可以计算出列宽:

width: (flickable.width - flickable.spacing) / flickable.column

因此,其实未知的仅有卡片高度:

image

如图所示,卡片高度由三部分组成:【封面图片高度】+【标题高度】+【卡片信息高度】

height: coverRealHeight + titleHeight + infoHeight

现在有了宽高,接下来只要计算出 位置 (x, y) 即可:

    if (flickable.currentColumn == flickable.column) {flickable.currentColumn = 0;flickable.currentX = 0;for (let i = 0; i < flickable.column; i++) {flickable.currentY[i] += flickable.prevHeight[i];}}x = flickable.currentX;y = flickable.currentY[flickable.currentColumn];flickable.prevHeight[flickable.currentColumn] = Math.round(height + flickable.spacing);print(flickable.currentColumn, flickable.currentX, flickable.prevHeight, flickable.currentY);flickable.currentX += coverRealWidth + flickable.spacing;flickable.currentColumn++;let max = 0;for (let j = 0; j < flickable.column; j++) {max = Math.max(flickable.prevHeight[j] + flickable.currentY[j]);}flickable.contentHeight = max;

x 坐标计算思路是:从左往右依次增加一个卡片宽度,到达本行最后一个卡片时置零即可。

y 坐标计算思路是:记录下本行卡片高度数组 prevHeight[column],到达本行最后一个卡片时计算下行卡片 y 坐标数组 currentY[column],而首行则为 0。

至此,Rect (x, y, width, height) 全部已知,我们可以直接利用 Repeater 轻松实例化出来:

Repeater {id: repeatermodel: ListModel {id: listModelComponent.onCompleted: {flickable.loadMore();}}delegate: Rectangle {id: rootItemwidth: (flickable.width - flickable.spacing) / flickable.columnheight: coverRealHeight + titleHeight + infoHeightradius: 4clip: trueproperty real aspectRatio: coverWidth / coverHeightproperty real coverRealWidth: widthproperty real coverRealHeight: width / aspectRatioproperty real titleWidth: widthproperty real titleHeight: titleText.heightproperty real infoWidth: widthproperty real infoHeight: 50Component.onCompleted: {if (flickable.currentColumn == flickable.column) {flickable.currentColumn = 0;flickable.currentX = 0;for (let i = 0; i < flickable.column; i++) {flickable.currentY[i] += flickable.prevHeight[i];}}x = flickable.currentX;y = flickable.currentY[flickable.currentColumn];flickable.prevHeight[flickable.currentColumn] = Math.round(height + flickable.spacing);print(flickable.currentColumn, flickable.currentX, flickable.prevHeight, flickable.currentY);flickable.currentX += coverRealWidth + flickable.spacing;flickable.currentColumn++;let max = 0;for (let j = 0; j < flickable.column; j++) {max = Math.max(flickable.prevHeight[j] + flickable.currentY[j]);}flickable.contentHeight = max;}Column {Item {id: coverPortwidth: coverRealWidthheight: coverRealHeightImage {anchors.fill: parentanchors.topMargin: rootItem.radiussource: cover}}Item {id: titlePortwidth: titleWidthheight: titleText.heightText {id: titleTextwidth: parent.widthwrapMode: Text.WrapAnywheretext: titlefont.family: "微软雅黑"font.pointSize: 14}}Item {id: infoPortwidth: infoWidthheight: infoHeightRowLayout {anchors.fill: parentCircularImage {id: headLayout.preferredWidth: parent.height - 5Layout.preferredHeight: parent.height - 5Layout.leftMargin: 5Layout.alignment: Qt.AlignVCentersource: "file:/C:/Users/mps95/Desktop/head.jpg"}Text {Layout.fillWidth: trueLayout.fillHeight: truetext: "用户" + userfont.pointSize: 14verticalAlignment: Text.AlignVCenterelide: Text.ElideRight}Text {Layout.preferredWidth: 100Layout.preferredHeight: parent.heightLayout.rightMargin: 5text: (like ? "🩷" : "🤍") + " " + Math.round(Math.random() * 1000)font.pointSize: 14horizontalAlignment: Text.AlignRightverticalAlignment: Text.AlignVCenterproperty int like: Math.round(Math.random())}}}}}
}

loadMore() 是向后台请求更多的卡片数据,这部分需要根据实际需求进行改造,我这里就简单生成了一些模拟数据:

function loadMore() {//这部分来自后台请求, 必须知道封面宽高let titleList = ["单行标题: 测试测试测试测试","双行标题: 测试测试测试测试测试测测试测试测试测试测试测试","三行标题: 测试测试测试测试测试测测试测试测试测试测试测试测试测试测试测试测试测试测试"];for (let i = 0; i < 10; i++) {let userId = Math.round(Math.random() * 100000);let type = Math.round(Math.random());  //0 image / 1 videolet cover = "file:/C:/Users/mps95/Desktop/素材/动漫图片/img2" + i + ".jpg"; //封面, 无论视频还是图片都需要有let url = cover;if (type == 1) {//url = "file:/test.mp4";}let object = {type: type,cover: cover,user: userId,url: url,title: titleList[Math.round(Math.random() * 2)],coverWidth: 300,coverHeight: (type + 2) * 100 + Math.round(Math.random() * 3) * 80};jsonData.push(object);listModel.append(object);}
}

【结语】

最后:项目链接(多多star呀..⭐_⭐):

Github 的 WaterfallFlow 瀑布流视图(并且可以自适应),类似小红书

注意: 测试用的图片没有包含在内,请改为自己的测试集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/795078.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rocky9

Rocky Linux 9.4 部署Zabbix 7.0 1-1.检测源 wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm #下载epel的源 rpm -ivh epel-release-latest-8.noarch.rpm #epel安装 rpm -Uvh https://repo.zabbix.com/zabbix/7.0/rocky/9/x86_64/zabbix-releas…

洛谷题单指南-常见优化技巧-P1714 切蛋糕

原题链接:https://www.luogu.com.cn/problem/P1714 题意解读:求长度不超过m的最大子段和 解题思路: 1、暴力法 设a[N]表示原数组,s[N]是a[N]的前缀和,对于每一个元素s[i],计算其与前m个元素之差,取差值最大值,用代码表示: for(int i = 1; i <= n; i++) {for(int j …

【专题】2024年中国折叠屏手机市场与消费趋势研究报告合集PDF分享(附原数据表

原文链接:https://tecdat.cn/?p=37645 中国智能手机市场目前仍处于整体增长瓶颈期,增长复苏未达预期,消费者换机预期周期不断延长,使得行业对破局点的探寻更为紧迫。与此同时,中端消费者购机呈现出消费降级与升级的分化态势,不过更多人会选择体验更好、配置更优的产品以…

Goby 漏洞发布|(CVE-2024-45195)Apache OFBiz /viewdatafile 代码执行漏洞【已复现】

漏洞名称:Apache OFBiz /viewdatafile 代码执行漏洞(CVE-2024-45195) English Name:Apache OFBiz /viewdatafile Code Execution Vulnerability(CVE-2024-45195) CVSS core: 8.0 漏洞描述: Apache OFBiz是一个开源企业资源规划(ERP)系统。它提供了一套企业应用程序,…

navicat无法连接远程的mysql--Host ‘xx.xx.xx.xx‘ is not allowed to connect to this MySQL server“

之前在远程虚拟机上面部署了mysql,想在本地客户端使用navicat连接数据库,结果提示:host xxx is not allowed to connect to this mysql server解决 出现这个提示,是由于我们使用root用户登录时,没有给root用户设置能访问的机器,所以我们设置一下,就可以了。1:登录mysql…

jQuery中开发插件

页面代码<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script s…

ubuntu 使用命令行查看硬件信息

ubuntu 使用命令行查看硬件信息 CPU cat /proc/cpuinfo其中,model name就显示了cpu的型号,cpu cores显示cpu的所有物理核心数量。 内存 cat /proc/meminfo其中,MemTotal就显示总内存大小,这里为32GB内存,SwapTotal显示了交换分区的内存大小,这里为 2GB。 硬盘大小 df -h可…

易百纳ss928开发板移植自训练模型跑通yolov5算法

ss928平台移植官方yolov5s算法参考文章:https://www.ebaina.com/articles/140000017418,这位大佬也开源了代码,gitee链接:https://gitee.com/apchy_ll/ss928_yolov5s 本文在参考上述文章的基础上,将官方yolov5s模型跑通,验证推理图片正确,然后移植自训练的推理模型,在移…

hyperworks软件许可优化解决方案

Hyperworks软件介绍 Altair 仿真驱动设计改变了产品开发,使工程师能够减少设计迭代和原型测试。提升科学计算能力扩大了应用分析的机会,使大型设计研究能够在限定的项目时间完成。现在,人工智能在工程领域的应用再次改变了产品开发。基于物理场的仿真驱动设计与机器学习相结…

Xcode 16 RC (16A242) 发布下载,正式版下周公布

Xcode 16 RC (16A242) 发布下载,正式版下周公布Xcode 16 RC (16A242) - Apple 平台 IDE IDE for iOS/iPadOS/macOS/watchOS/tvOS/visonOS 请访问原文链接:https://sysin.org/blog/apple-xcode-16/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.orgXcode 16 的新…

md5拓展攻击

md5拓展攻击 【工具】hash-ext-attack/img/img_1.png at master shellfeel/hash-ext-attack GitHub 【攻击方法例题】https://ctf.org.cn/2019/11/19/哈希长度扩展攻击以及HashPump安装使用和两道题目/ 实际中的利用条件如下:基于哈希的消息认证码 (MAC):长度扩展攻击的关键…

JAVA+VUE实现动态表单配置

功能描述: 资产管理系统中,在资产分类中,给同一种类型的资产配置定制化的表单项,并实现不同类型显示不同的数据,如图所示:数据库设计部分: 1.表单项表CREATE TABLE `dct_smp`.`t_asset_product_definitions` (`id` bigint NOT NULL,`product_id` bigint NOT NULL COMMEN…