swiftui中封装一个carditem视图,结合toolbar实现滚动的瀑布流,仿小红书首页

news2024/9/22 12:17:54

实现的效果如上图所示,支持左右滑动切换页面,也支持点击顶部的toolbar菜单切换页面,每个页面里面的每一项都是一个carditem.swift,这是我封装的一个card组件,用于展示每一个card内容,carditem.swift内容如下:

//
//  CardItem.swift
//  SwiftBook
//
//  Created by Song on 2024/7/6.
//

import SwiftUI

struct CardItem: View {
    // 传递过来的图片和昵称
    var preImg = ""
    var avatar = ""
    var nickname = ""
    var distance = ""

    var body: some View {
        VStack {
            Image(preImg)
                .resizable()
                .aspectRatio(contentMode: .fit)
            HStack {
                HStack {
                    Image(avatar)
                        .resizable()
                        .frame(width: 20, height: 20)
                        .aspectRatio(contentMode: .fit)
                        .mask(Circle())
                    Text(nickname)
                }
                Spacer()
                Text("\(distance)km")
            }
        }
        .padding()
        .background(.white)
        .cornerRadius(10)
    }
}

#Preview {
    CardItem()
}

这个组件封装出来的效果如图所示:里面使用到的就是水平布局和垂直布局,还有一个Image组件


 

首页实现

然后就是首页里面的toolbar使用,以及NavigationStack和TabView,还有tabViewStyle,还有navigationBarTitleDisplayMode,还有ToolbarItem。简单讲一下使用他们的必要性以及作用。

NavigationStack是导航栈,要配合TabView一起使用,才能达到TabView的效果。

TabView:是实现点击每一项toolbar实现页面切换的必备视图

tabViewStyle:是为了使用tabview的page样式,以此实现页面切换的效果,并设置indexDisplayMode为never,让切换页面之间不显示小白点,就是轮播图。还有一种是点击底部tab的效果。

navigationBarTitleDisplayMode:为了让顶部toolbar和内容之间没有空白间隙,设置inline模式。

toolbar+ToolbarItem:为了实现顶部的toolbar菜单效果。还有顶部右侧的搜索图标显示。

首页代码内容:

//
//  Hongshu.swift
//  SwiftBook
//
//  Created by Song on 2024/7/6.
//

import SwiftUI

struct Hongshu: View {
    @State var current = 0
    var body: some View {
        NavigationStack {
            ScrollView(content: {
                TabView(selection: $current) {
                    HStack(content: {
                        VStack(content: {
                            CardItem(preImg: "juzi", avatar: "juzi", nickname: "11111", distance: "555")
                            CardItem(preImg: "putao", avatar: "putao", nickname: "putao", distance: "11")
                            CardItem(preImg: "shanchu", avatar: "xigua", nickname: "山竹", distance: "53")
                            Spacer()
                        })
                        VStack(content: {
                            CardItem(preImg: "hongyou", avatar: "liulian", nickname: "liula", distance: "11")
                            CardItem(preImg: "taozi", avatar: "xigua2", nickname: "山竹", distance: "53")
                            CardItem(preImg: "lizhi", avatar: "xigua2", nickname: "山竹", distance: "53")
                            Spacer()
                        })
                    })
                    .padding(.horizontal)
                    .tag(0)
                    HStack(content: {
                        VStack(content: {
                            CardItem(preImg: "taozi", avatar: "taozi", nickname: "11111", distance: "555")
                            CardItem(preImg: "xigua", avatar: "xigua", nickname: "putao", distance: "11")
                            CardItem(preImg: "hongyou", avatar: "xigua", nickname: "山竹", distance: "53")
                            Spacer()
                        })
                        VStack(content: {
                            CardItem(preImg: "liulian", avatar: "liulian", nickname: "liula", distance: "11")
                            CardItem(preImg: "xigua2", avatar: "xigua2", nickname: "山竹", distance: "53")
                            Spacer()
                        })
                    })
                    .padding(.horizontal)
                    .tag(1)
                    HStack(content: {
                        VStack(content: {
                            CardItem(preImg: "xigua", avatar: "taozi", nickname: "11111", distance: "555")
                            CardItem(preImg: "default", avatar: "xigua", nickname: "putao", distance: "11")
                            CardItem(preImg: "xigua2", avatar: "xigua", nickname: "山竹", distance: "53")
                            Spacer()
                        })
                        VStack(content: {
                            CardItem(preImg: "liulian", avatar: "liulian", nickname: "liula", distance: "11")
                            CardItem(preImg: "taozi", avatar: "xigua2", nickname: "山竹", distance: "53")
                            Spacer()
                        })
                    })
                    .padding(.horizontal)
                    .tag(2)
                }
                .tabViewStyle(.page(indexDisplayMode: .never))
                .frame(width: UIScreen.main.bounds.width,
                       height: UIScreen.main.bounds.height)
            })
            .background(.gray.opacity(0.3))
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .principal, content: {
                    HStack {
                        Text("首页")
                            .foregroundColor(
                                current == 0 ? .blue : .black)
                            .onTapGesture {
                                current = 0
                            }
                        Text("附近")
                            .foregroundColor(
                                current == 1 ? .blue : .black)
                            .onTapGesture {
                                current = 1
                            }
                        Text("推荐")
                            .foregroundColor(
                                current == 2 ? .blue : .black)
                            .onTapGesture {
                                current = 2
                            }
                    }
                })
                ToolbarItem(placement: .topBarTrailing, content: {
                    HStack {
                        Image(systemName: "magnifyingglass")
                    }
                })
            }
            .tag("home")
        }
    }
}

#Preview {
    Hongshu()
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Altium】AD-网络版一个用户非人为异常占用多个License的解决方法

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 当出现一个用户同时占用多个授权,又无法单独释放一个授权的情况下,该如何解决。 2、 问题场景 一个用户获取网络版授权后,AD会自动重复获取授权,直到该license下所有授…

Qt 线程 QThread类详解

Qt 线程中QThread的使用 在进行桌面应用程序开发的时候, 假设应用程序在某些情况下需要处理比较复杂的逻辑, 如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作。这种情况下就需要使用多线程,其中一个…

盲盒小程序开发:互联网下的的盲盒发展

近些年来,盲盒行业发展的非常迅速,盲盒的不确定性吸引了无数玩家,盲盒的市场规模逐渐扩大,盲盒品牌也在不断出现,为盲盒消费者带来更多的新鲜体验, 随着互联网小程序的的快速发展,盲盒小程序为…

告别‘找文件’大战,可道云teamOS分区管理,文件秒定位

在数字化时代,数据已经成为企业最宝贵的资产之一。 如何高效、安全地管理这些数据,成为了每一个企业必须面对的问题。 企业网盘作为一种便捷的数据存储和共享工具,已经成为了企业日常运营中不可或缺的一部分。 然而,传统的网盘管…

人员定位系统于不同场景的实际应用

人员定位系统的应用,尽管还没有做到大范围的普及,但是这一系统在不同企业,不同单位的实际应用效果还是很好的,所以人员定位系统也应用于不同场景当中了,那么,本文就来讲讲这一系统在不同场景的实际应用。 人…

汽车信息安全--欧盟汽车法规

目录 General regulation 信息安全法规 R155《网络安全及网络安全管理系统》解析 R156《软件升级与软件升级管理系统》解析 General regulation 欧洲的汽车行业受到一系列法律法规的约束,包括 各个方面包括: 1.安全要求:《通用安全条例&a…

【Qt】对话框

1、自定义对话框并赋予ui界面,用按钮呼出 https://www.bilibili.com/video/BV1rK411A7qi/?spm_id_from333.999.0.0&vd_sourcefd6555f02904e7fa85526a2ff4b8b66e 新建 - 文件和类 - Qt - Qt设计师界面类在原来的父窗口cpp文件中初始化新窗口并调用exec显示模态…

什么软件能够监控电脑?五大好用监控电脑软件推荐

在当今的企业管理中,电脑监控软件已经成为必不可少的工具。它们不仅能提升员工的工作效率,还能保护企业的核心数据,防止信息泄露。以下将介绍几款市场上备受好评的电脑监控软件,特别是固信软,帮助企业找到最适合的解决…

软件测试下的AI之路(5)

😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。 📡主页地址:【Austin_zhai】 🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。 💎声明:博主日常工作较为繁忙,文章会不定期更新,各类行业或职场问题欢迎大家…

掌握MySQL基础命令:数据更新操作详细操作(数据的增删改)

MySQL数据修改是指使用SQL语句(如UPDATE、INSERT、DELETE)对数据库表中的数据进行更改、添加或删除的操作,常见的操作包括更新表中的记录、插入新记录以及删除现有记录 。 一、数据插入 1插入完整的数据记录 2插入非完整的数据记录 3插入多…

SQL 之 concat_ws和concat的区别

concat_ws和concat都是用于连接字符串的函数,但它们在使用上有一些区别: 一、concat、concat_ws函数格式: concat格式: concat(参数1,参数2,…参数n),如果要加’分隔符’直接写在 各参数中间就…

【知网CNKI-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…

【Git基本操作】创建本地仓库 | 配置本地仓库 | 认识工作区、暂存区、版本库、对象库 | add和commit操作

目录 1.创建Git本地仓库 1.1创建仓库 1.2创建和初始化Git本地仓库 1.3查看隐藏目录.git 2.配置本地仓库 2.1新增配置 2.2删除重置配置 2.3查看配置选项 2.4全局范围的新增和删除配置 3.工作区、暂存区、版本库、对象库 ​4.add操作和commit操作 4.1add操作 4.2com…

AI 大模型系统实战

AI 大模型是什么? 维基百科对基础模型的定义是这样的,基础模型是一种大型机器学习模型,通常在大量数据上进行大规模训练(通过自监督学习或半监督学习),以使它可以适应各类下游任务。因此,它需要…

从入门到精通:Shopee,lazada,temu自养号测评成本、步骤、技巧详解

测评对于卖家来说是一种成本低回报快的推广方式,可以减少高额的平台广告费用,因此是一种很好的辅助手段,对商品的曝光、流量、转化和权重等方面起到了很好的辅助作用 建议还是自己精养一批账号,账号在自己手里比较安全可控&#…

重塑消费体验:探索绿色消费增值模式的新篇章

我是吴军,就职于一家在数字创新领域屡获殊荣的软件企业,担任高级产品策略师。今天,我满怀热忱,想与您一同揭开一种前沿且极具吸引力的商业模式面纱——那就是绿色消费增值模式,一个正逐步改变我们消费习惯与商业生态的…

一.1 信息就是位+上下文

hello程序的生命周期是从一个源程序(或者说源文件)开始的,即程序员通过编辑器创建并保存的文本文件,文件名是hello.c。源程序实际上就是一个由0和1组成的位(又称为比特)序列,8个位被组织成一组&…

平面法向的角度表示以及坐标系变换

1.根据法线计算法线的垂直角sint和法线在水平投影与x轴的夹角phi double phi atan2(normal(1) , normal(0)); // atan2(y,x), 计算法向在xy平面上的投影和x轴之间的夹角double sint asin(normal(2)); //理论上是z轴和 该法向向量之间的夹角 2.根据角度计算法线 Eigen::Vec…

AnaPico为众多工厂产线老化测试提供高效经济的微波解决方案

在电子设备的生产中,老化测试在整个使用寿命期间的可靠性和对声明参数的保证起着重要作用,尤其是在特殊应用(国防和航天工业、电信、医药等)方面。即使经过成功的参数和功能测试,在实际操作条件下使用时也有可能出现设…

集芯微电推出固定输出2V|2.5V|3V|3.3V|4V|4.5V|5V_输入最大16V_10 ppm/°C低噪声低漂移高精度基准电压源

1特征 •低温漂移:3 ppm/C(典型) •高精度:最大0.1% •低噪声:7.5μVPP/V •低IQ:2 mA(典型) •工作温度范围:-40C至125C •高输出电流:10 mA •微型包…