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

这篇具有很好参考价值的文章主要介绍了【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/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 3/7部分-搭建TabBar - 效果

详细

一、运行效果

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

二、项目结构图

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

三、程序实现 - 过程

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

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

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

1.1.引入资源文件和颜色

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

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

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

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

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

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

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

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

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

主要是:

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

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

【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram
【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar,# SwiftUI项目,# SwiftUI项目+Firebase,swiftui,ios,swift,Firebase,Instagram

Code

ContentView - 主窗口

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

import SwiftUI

struct 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 SwiftUI

struct 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)
    }
    
    // 固定的内容
    @ViewBuilder
    func SongList()->some View{
        VStack(spacing: 25){
            ForEach($_albums){$album in
                
                HStack(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 in
            return album.id == currentAlbum.id
        } ?? 0
    }
    
    // 头部视图
    @ViewBuilder
    func HeaderView()->some View{
        GeometryReader{proxy in
            let minY = proxy.frame(in: .named("SCROLL")).minY
            let size = proxy.size
            let 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)
    }
    
    // 固定在头部
    @ViewBuilder
    func 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 in
                    VStack(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的滚动 偏移量的改变文章来源地址https://www.toymoban.com/news/detail-720182.html

//
//  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)
     }
 }
 
 ⭐️如果是继承ViewModifier
 struct 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 = 0
    
    func body(content: Content) -> some View {
        content
            .overlay {
                GeometryReader{proxy in
                    Color.clear
                        .preference(key: OffsetKey.self, value: proxy.frame(in: .named("SCROLL")).minY)
                        .onPreferenceChange(OffsetKey.self) { value in
                            if startValue == 0{
                                startValue = value
                            }
                            print(value);

                            offset = (value - (returnFromStart ? startValue : 0))
                            
                            print("offset is \(offset)");

                        }
                }
            }
    }
}

// 偏好的关键
struct OffsetKey: PreferenceKey{
    static var defaultValue: CGFloat = 0
    
    static 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().uuidString
    var albumName: String
    var albumImage : String
    var 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"),
    
]

到了这里,关于【SwiftUI模块】0060、SwiftUI基于Firebase搭建一个类似InstagramApp 3/7部分-搭建TabBar的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 写了一个 SRE 调试工具,类似一个小木马

    远程操作机器有时会比较麻烦,我写了一个工具,主要功能:1.远程执行命令 2.上传下载文件。是一个 Web Server,通过 HTTP 请求来操作机器,类似一个小木马。当然,因为是一个 Web Server,所以也提供了打印 HTTP 请求的能力,方便调试 Webhook 场景。下面给大家演示一下。 工具代

    2024年04月22日
    浏览(56)
  • 基于Maven和IntelliJ IDEA搭建多模块微服务

    基于Spring Boot、Spring Cloud、Spring Cloud Alibaba的微服务开发,组件众多。因此,在创建项目伊始,就应当考虑版本的管理。以Spring Boot的版本升级发布为基础,Spring Cloud的版本升级发布,会匹配Spring Boot升级发布的版本。Spring Cloud Alibaba版本升级发布,会匹配Spring Boot和Spring Cloud的

    2024年03月23日
    浏览(58)
  • [visionOS][Apple Vision Pro][SwiftUI] 定义一个UIImage变量,可动态改变,并显示在Image控件

    实际上,不需要加.onChange也可以的,这个只是响应myImage变化,跟Image更新图片没关系。 用@State标记一个属性时,SwitfUI会自动监听这个属性的变更,当这个属性发生改变,SwiftUI 会自动重新计算绘制视图。

    2024年02月16日
    浏览(46)
  • 一个基于.NET Core构建的简单、跨平台、模块化的商城系统

    今天大姚给大家分享一个基于.NET Core构建的简单、跨平台、模块化、完全开源免费(MIT License)的商城系统:Module Shop。 商品:分类、品牌、单位、选项(销售属性)、属性、属性模板、属性组。 销售:订单、物流。 内容:首页配置、评论、回复。 配置:国家、用户、仓库

    2024年03月27日
    浏览(175)
  • Latte:一个类似Sora的开源视频生成项目

    前段时间OpenAI发布的Sora引起了巨大的轰动,最长可达1分钟的高清连贯视频生成能力秒杀了一众视频生成玩家。因为Sora没有公开发布,网上对Sora的解读翻来覆去就那么多,我也不想像复读机一样再重复一遍了。 本文给大家介绍一个类似Sora的视频生成项目:Latte。为什么说它

    2024年03月11日
    浏览(46)
  • 用Vue仿了一个类似抖音的App

    大家好,我是 Java陈序员 。 今天,给大家介绍一个基于 Vue3 实现的高仿抖音开源项目。 关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。 douyin —— 一个基于 Vue、Vite 实现,模仿抖音的移动端短视频项目。 这个项目的作者原

    2024年04月08日
    浏览(36)
  • 基于Flask快速搭建一个管理系统

    1.3.1 普通使用 1.3.2 带有名分组 1.3.3 带请求限制 1.3.4 带别名,默认别名是函数名 1.3.5 路由其他参数(默认string) 1.3.6 路由的本质 1.3.7  app.add_url_rule参数 1.5.1 返回时的格式 1.5.2 坑1,出现找不到模板,解决办法 项目下面是否有templates文件夹,你的html文件是否放进了里面; temp

    2023年04月15日
    浏览(36)
  • 一图看懂 multidict 模块:类似于字典的键值对集合,键可以多次出现,资料整理+笔记(大全)

    本文由 大侠(AhcaoZhu)原创,转载请声明。 链接: https://blog.csdn.net/Ahcao2008 全文介绍系统内置 multidict 模块(类似于字典的键值对集合,键可以多次出现)、函数、类及类的方法和属性。 它通过代码抓取并经AI智能翻译和人工校对。 是一部不可多得的权威字典类工具书。它是系列集

    2024年02月04日
    浏览(86)
  • 基于Python+Django,我搭建一个视频点播平台

    学习过程中,遇到问题可以咨询作者 功能介绍 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。 整个平台包括前台和后台两个部分。 前台功能包括:首页、视频列表页面、视频详情页、用户中心模块。 后台功能包括:总览、视频管理、

    2024年01月18日
    浏览(36)
  • 封装一个类似微信通讯录带有字母检索功能的vue组件

    这里我们直接使用 scrollIntoView 方法 该方法将调用它的元素滚动到浏览器窗口的可见区域 element.scrollIntoView(); // 等同于element.scrollIntoView(true) element.scrollIntoView(alignToTop); //布尔参数 element.scrollIntoView(scrollIntoViewOptions); //对象参数 分析一下功能就知道很简单了。 首先需要

    2024年02月12日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包