【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 2/7部分-搭建TabBar

SwiftUI模块系列 - 已更新60篇
SwiftUI项目 - 已更新5个项目
往期Demo源码下载

技术:SwiftUI、SwiftUI4.0、Instagram、Firebase
运行环境:
SwiftUI4.0 + Xcode14 + MacOS12.6 + iPhone Simulator iPhone 14 Pro Max

SwiftUI基于Firebase搭建一个类似InstagramApp 2/7部分-搭建TabBar

    • 概述
    • 详细
      • 一、运行效果
      • 二、项目结构图
      • 三、程序实现 - 过程
        • 1.创建一个项目命名为 `SpotifyResponvieUI`
        • 1.1.引入资源文件和颜色
        • 2. 创建一个虚拟文件`New Group` 命名为 `View`
        • 3. 创建一个虚拟文件`New Group` 命名为 `Model`
        • 4. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`Album` 并且继承`Identifiable`
        • 5. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`Home`
        • 6. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`OffsetModifier`
      • Code
        • ContentView - 主窗口
        • Home - 主页
        • OffsetModifier - `主要是监听ScrollView的滚动`
        • Album - 模型

概述

使用SwiftUI基于Firebase搭建一个类似InstagramApp 2/7部分-搭建TabBar - 效果

详细

一、运行效果

请添加图片描述

二、项目结构图

在这里插入图片描述

三、程序实现 - 过程

思路:
1.创建头部模块 进行测试上下滚动拥有放大缩小效果
2.搭建分类模块 固定在头部下面
3.搭建列表模块
4.监听滚动偏移的操作

1.创建一个项目命名为 SpotifyResponvieUI

在这里插入图片描述
在这里插入图片描述

1.1.引入资源文件和颜色

颜色
BG #281A1A
Green #4DD037
随机图片9张
个人大图背景1张
logo1张

在这里插入图片描述

2. 创建一个虚拟文件New Group 命名为 View

在这里插入图片描述
在这里插入图片描述

3. 创建一个虚拟文件New Group 命名为 Model

在这里插入图片描述
在这里插入图片描述

4. 创建一个文件New File 选择SwiftUI View类型 命名为Album 并且继承Identifiable

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5. 创建一个文件New File 选择SwiftUI View类型 命名为Home

主要是:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

6. 创建一个文件New File 选择SwiftUI View类型 命名为OffsetModifier

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Code

ContentView - 主窗口

主要是展示主窗口Home和设置暗黑模式

import SwiftUIstruct ContentView: View {var body: some View {Home()// 永远是黑暗模式.preferredColorScheme(.dark)}}struct ContentView_Previews: PreviewProvider {static var previews: some View {ContentView()}
}
Home - 主页

思路

  1. 主要就是展示大图背景 + 固定的分类 + 列表模块
//
//  Home.swift
//  SpotifyResponvieUI (iOS)
//
//  Created by lyh on 2022/8/23.
//import SwiftUIstruct Home: View {@State var currentType: String = "Popular"// 光滑滑动效果@Namespace var animation@State var _albums: [Album] = albums// x,y@State var headerOffsets: (CGFloat,CGFloat) = (0,0)var body: some View {ScrollView(.vertical, showsIndicators: false) {VStack(spacing: 0){HeaderView()// 带内容的固定标题LazyVStack(pinnedViews: [.sectionHeaders]) {Section {SongList()} header: {PinnedHeaderView().background(Color.black).offset(y: headerOffsets.1 > 0 ? 0 : -headerOffsets.1 / 8).modifier(OffsetModifier(offset: $headerOffsets.0, returnFromStart: false)).modifier(OffsetModifier(offset: $headerOffsets.1))}}}}.overlay(content: {Rectangle().fill(.black).frame(height: 50).frame(maxHeight: .infinity,alignment: .top).opacity(headerOffsets.0 < 5 ? 1 : 0)}).coordinateSpace(name: "SCROLL").ignoresSafeArea(.container, edges: .vertical)}// 固定的内容@ViewBuilderfunc SongList()->some View{VStack(spacing: 25){ForEach($_albums){$album inHStack(spacing: 12){Text("#\(getIndex(album: album) + 1)").fontWeight(.semibold).foregroundColor(.gray)Image(album.albumImage).resizable().aspectRatio(contentMode: .fill).frame(width: 55, height: 55).clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))VStack(alignment: .leading, spacing: 8) {Text(album.albumName).fontWeight(.semibold)Label {Text("65,587,909")} icon: {Image(systemName: "beats.headphones").foregroundColor(.white)}.foregroundColor(.gray).font(.caption)}.frame(maxWidth: .infinity,alignment: .leading)Button {album.isLiked.toggle()} label: {Image(systemName: album.isLiked ? "suit.heart.fill" : "suit.heart").font(.title3).foregroundColor(album.isLiked ? Color("Green") : .white)}Button {} label: {Image(systemName: "ellipsis").font(.title3).foregroundColor(.white)}}}}.padding().padding(.top,25).padding(.bottom,150)}func getIndex(album: Album)->Int{return _albums.firstIndex { currentAlbum inreturn album.id == currentAlbum.id} ?? 0}// 头部视图@ViewBuilderfunc HeaderView()->some View{GeometryReader{proxy inlet minY = proxy.frame(in: .named("SCROLL")).minYlet size = proxy.sizelet height = (size.height + minY)Image("Ariana").resizable().aspectRatio(contentMode: .fill).frame(width: size.width,height: height > 0 ? height : 0,alignment: .top).overlay(content: {ZStack(alignment: .bottom) {// 调暗文本内容LinearGradient(colors: [.clear,.black.opacity(0.8)], startPoint: .top, endPoint: .bottom)VStack(alignment: .leading, spacing: 12) {Text("宇夜iOS").font(.callout).foregroundColor(.gray)HStack(alignment: .bottom, spacing: 10) {Text("Ariana Grande").font(.title.bold())Image(systemName: "checkmark.seal.fill").foregroundColor(.blue).background{Circle().fill(.white).padding(3)}}Label {Text("Monthly Listeners").fontWeight(.semibold).foregroundColor(.white.opacity(0.7))} icon: {Text("62,354,659").fontWeight(.semibold)}.font(.caption)}.padding(.horizontal).padding(.bottom,25).frame(maxWidth: .infinity,alignment: .leading)}}).cornerRadius(15).offset(y: -minY)}.frame(height: 250)}// 固定在头部@ViewBuilderfunc PinnedHeaderView()->some View{let types: [String] = ["Popular","Albums","Songs","Fans also like","About"]ScrollView(.horizontal, showsIndicators: false) {HStack(spacing: 25){ForEach(types,id: \.self){type inVStack(spacing: 12){Text(type).fontWeight(.semibold).foregroundColor(currentType == type ? .white : .gray)ZStack{if currentType == type{RoundedRectangle(cornerRadius: 4, style: .continuous).fill(.white).matchedGeometryEffect(id: "TAB", in: animation)}else{RoundedRectangle(cornerRadius: 4, style: .continuous).fill(.clear)}}.padding(.horizontal,8).frame(height: 4)}.contentShape(Rectangle()).onTapGesture {withAnimation(.easeInOut){currentType = type}}}}.padding(.horizontal).padding(.top,25).padding(.bottom,5)}}
}struct Home_Previews: PreviewProvider {static var previews: some View {ContentView()}
}
OffsetModifier - 主要是监听ScrollView的滚动

用来监听ScrollView的滚动 偏移量的改变

//
//  OffsetModifier.swift
//  SpotifyResponvieUI (iOS)
//
//  Created by lyh on 2022/8/23.
//import SwiftUI// 继承于 ViewModifier 最主要是能方便扩展一些常见的设置属性
/*比如 给Text设置字体\背景颜色\阴影效果extension Text {func songStyle() -> some View {self.font(.system(size: 24, weight: .bold)).foregroundColor(.white).shadow(radius: 20)}}⭐️如果是继承ViewModifierstruct SongTextViewModifier: ViewModifier {func body(content: Content) -> some View {content.font(.system(size: 24, weight: .bold)).foregroundColor(.white).shadow(radius: 20)}}然后直接通过Text(song).modifier(SongTextViewModifier())设置*/struct OffsetModifier: ViewModifier {@Binding var offset: CGFloat// 可选从0返回值var returnFromStart: Bool = true@State var startValue: CGFloat = 0func body(content: Content) -> some View {content.overlay {GeometryReader{proxy inColor.clear.preference(key: OffsetKey.self, value: proxy.frame(in: .named("SCROLL")).minY).onPreferenceChange(OffsetKey.self) { value inif startValue == 0{startValue = value}print(value);offset = (value - (returnFromStart ? startValue : 0))print("offset is \(offset)");}}}}
}// 偏好的关键
struct OffsetKey: PreferenceKey{static var defaultValue: CGFloat = 0static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {value = nextValue()}
}
Album - 模型
//
//  Album.swift
//  SpotifyResponvieUI (iOS)
//
//  Created by lyh on 2022/8/23.
//import SwiftUI// Ablum模型和样本数据
struct Album: Identifiable {var id = UUID().uuidStringvar albumName: Stringvar albumImage : Stringvar isLiked : Bool = false
}var albums : [Album] = [Album(albumName: "Positions", albumImage: "Album1"),Album(albumName: "The Best", albumImage: "Album2",isLiked: true),Album(albumName: "My Everything", albumImage: "Album3"),Album(albumName: "Yours Truly", albumImage: "Album4"),Album(albumName: "Sweetener", albumImage: "Album5",isLiked: true),Album(albumName: "Rain On Me", albumImage: "Album6"),Album(albumName: "Stuck With U", albumImage: "Album7"),Album(albumName: "7 rings", albumImage: "Album8",isLiked: true),Album(albumName: "Bang Bang", albumImage: "Album9"),]

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

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

相关文章

机器学习笔记 - 特斯拉的占用网络简述

一、简述 ​ 2022 年,特斯拉宣布即将在其车辆中发布全新算法。该算法被称为occupancy networks,它应该是对Tesla 的HydraNet 的改进。 自动驾驶汽车行业在技术上分为两类:基于视觉的系统和基于激光雷达的系统。后者使用激光传感器来确定物体的存在和距离,而视觉系统…

算法通关村第十一关青铜挑战——移位运算详解

大家好&#xff0c;我是怒码少年小码。 计算机到底是怎么处理数字的&#xff1f; 数字在计算机中的表示 机器数 一个数在计算机中的二进制表示形式&#xff0c;叫做这个数的机器数。 机器数是带符号的&#xff0c;在计算机用一个数的最高位存放符号&#xff0c;正数为0&am…

2310x86版本skia的第一个示例

我也懒得去编译了(我也编译不来),要下载的东西太多,而skia-build项目中没有x86版本. 所以从这里下载了别人的,编译方法. 下载后,要改两个地方: 1,SkRect文件中使用了max/min,删除相应的std:: 2,SkTFitsIn.h文件中的std::numeric_limits<typename sk_strip_enum<D>::ty…

【Java集合类面试八】、 介绍一下HashMap底层的实现原理

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 介绍一下HashMap底层的…

Linux防火墙Centos6的常用命令iptables

文章目录 一、iptables基础知识二、作者玩玩的配置文件三、iptables中常用的参数以及作用-j参数的动作类型 四、安装iptables五、iptables启动命令六、iptables命令结构命令例子默认执行方式执行iptables命令和写入配置文件两种方式的对比 相对常用的命令参考文档 一、iptables…

leetcode做题笔记200. 岛屿数量

给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以假设该网格的四条边…

数据安全与PostgreSQL:最佳保护策略

在当今数字化时代&#xff0c;数据安全成为了企业不可或缺的一环。特别是对于使用数据库管理系统&#xff08;DBMS&#xff09;的组织来说&#xff0c;确保数据的完整性、保密性和可用性至关重要。在众多DBMS中&#xff0c;PostgreSQL作为一个强大而灵活的开源数据库系统&#…

表存储数据模型:宽列和时间序列

表格存储是阿里云第一个分布式多模型数据库&#xff0c;是一种NoSQL数据库。目前&#xff0c;很多应用系统底层不再单纯依赖关系型数据库&#xff0c;而是根据不同的业务场景使用不同的数据库。例如&#xff0c;缓存KeyValue数据将存储在Redis中&#xff0c;文档数据将存储在Mo…

MySQL中的表操作,配置文件,储存引擎,数据类型

MySQL中的表操作 1 查库&#xff08;已密码登陆mysql&#xff09; show databases; 2 添加库 create database t1; 3 表操作 1选定操作库 use t1 2在库里添加表格式 create table t1(id int, name varchar(32), gender varchar(32),age int); 3往表里添加具体元素 insert…

webgis开发参考资料

一、ArcGIS相关 1、ArcGIS for Server 10.3.X 新型紧凑型缓存的解读和应用 http://zhihu.geoscene.cn/article/1038 2、arcgis server 紧促&#xff08;bundle&#xff09;格式缓存文件的读取 https://blog.csdn.net/abc553226713/article/details/8668839 3、ArcGIS 10.0紧…

智慧燃气巡检管理系统

我们知道燃气设施的巡检、巡查是运维工作中一项重要的基础工作&#xff0c;而巡检人员主要靠手动记录&#xff0c;回到公司后还得再进行录入归档、导入照片&#xff0c;然后打印装订等&#xff0c;涉及工作量也是不小的&#xff1b;还有人员更替&#xff0c;易造成人员对燃气设…

GPT-2源码实现及GPT-3、GPT-3.5、GPT-4及GPT-5内幕解析

GPT-2源码实现及GPT-3、GPT-3.5、GPT-4及GPT-5内幕解析 Gavin大咖微信:NLP_Matrix_Space 5.1 ChatGPT提示词流程解析 本节主要是跟大家剖析 GPT内部的源码,在进入源码及运行项目之前,我们先思考一下ChatGPT的机制,ChatGPT默认情况下使用的模型是GPT-3.5,作者在日常工作中使…

模型部署笔记--Pytorch-FX量化

目录 1--Pytorch-FX量化 2--校准模型 3--代码实例 3-1--主函数 3-2--prepare_dataloader函数 3-3--训练和测试函数 1--Pytorch-FX量化 Pytorch在torch.quantization.quantize_fx中提供了两个API&#xff0c;即prepare_fx和convert_fx。 prepare_fx的作用是准备量化&#…

supervisor的使用

一、supervisor简介 Supervisor是用Python开发的一套通用的进程管理程序&#xff0c;能将一个普通的命令行进程变为后台daemon&#xff0c;并监控进程状态&#xff0c;异常退出时能自动重启。它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动&#xff…

Leetcode 2909. Minimum Sum of Mountain Triplets II

Leetcode 2909. Minimum Sum of Mountain Triplets II 1. 解题思路2. 代码实现 题目链接&#xff1a;2909. Minimum Sum of Mountain Triplets II 1. 解题思路 这一题思路上就是一个累积数组的思路。 我们要找一个山峰结构&#xff0c;使得其和最小&#xff0c;那么我们只需…

【GWO-KELM预测】基于灰狼算法优化核极限学习机回归预测研究(matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Dapper中使用字符串作为动态参数查询时,结果不是预期的问题

1、如下图&#xff0c;c.industryId作为string类型当作参数传递&#xff0c;解析时会加单引号&#xff0c;即&#xff1a;”c.industryId“&#xff0c; 生成的查询语句就会变成 -- 这里把c.IndustryGroup 当成实际的值所以会查询不出数据 select b.Name,COUNT(c.Id) Num …

爬虫模拟用户登录

使用爬虫模拟用户登录过程一般包括以下几个步骤&#xff1a; 导入所需的库&#xff1a;一般需要导入requests和BeautifulSoup库来发送HTTP请求和解析HTML。 import requestsfrom bs4 import BeautifulSoup 发送GET请求获取登录页面&#xff1a;使用requests库发送GET请求&#…

Spring Boot OAuth 2.0整合详解

目录 一、Spring Boot 2.x 示例 1、初始化设置 2、设置重定向URI 3、配置 application.yml 4、启动应用程序 二、Spring Boot 2.x 属性映射 二、CommonOAuth2Provider 三、配置自定义提供者&#xff08;Provider&#xff09;属性 四、覆盖 Spring Boot 2.x 的自动配置…