SwiftUI模塊系列 - 已更新60篇
SwiftUI項(xiàng)目 - 已更新5個(gè)項(xiàng)目
往期Demo源碼下載
技術(shù):SwiftUI、SwiftUI4.0、Instagram、Firebase
運(yùn)行環(huán)境:
SwiftUI4.0 + Xcode14 + MacOS12.6 + iPhone Simulator iPhone 14 Pro Max
概述
使用SwiftUI基于Firebase搭建一個(gè)類似InstagramApp 2/7部分-搭建TabBar - 效果
詳細(xì)
一、運(yùn)行效果
二、項(xiàng)目結(jié)構(gòu)圖
三、程序?qū)崿F(xiàn) - 過程
思路:
1.創(chuàng)建頭部模塊 進(jìn)行測試上下滾動(dòng)擁有放大縮小效果
2.搭建分類模塊 固定在頭部下面
3.搭建列表模塊
4.監(jiān)聽滾動(dòng)偏移的操作
1.創(chuàng)建一個(gè)項(xiàng)目命名為 SpotifyResponvieUI
1.1.引入資源文件和顏色
顏色
BG#281A1A
Green#4DD037
隨機(jī)圖片9張
個(gè)人大圖背景1張
logo1張
2. 創(chuàng)建一個(gè)虛擬文件New Group
命名為 View
3. 創(chuàng)建一個(gè)虛擬文件New Group
命名為 Model
4. 創(chuàng)建一個(gè)文件New File
選擇SwiftUI View
類型 命名為Album
并且繼承Identifiable
5. 創(chuàng)建一個(gè)文件New File
選擇SwiftUI View
類型 命名為Home
主要是:
6. 創(chuàng)建一個(gè)文件New File
選擇SwiftUI View
類型 命名為OffsetModifier
Code
ContentView - 主窗口
主要是展示主窗口
Home
和設(shè)置暗黑模式
import SwiftUI
struct ContentView: View {
var body: some View {
Home()
// 永遠(yuǎn)是黑暗模式
.preferredColorScheme(.dark)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Home - 主頁
思路文章來源:http://www.zghlxwxcb.cn/news/detail-720198.html
- 主要就是展示大圖背景 + 固定的分類 + 列表模塊
//
// Home.swift
// SpotifyResponvieUI (iOS)
//
// Created by lyh on 2022/8/23.
//
import SwiftUI
struct Home: View {
@State var currentType: String = "Popular"
// 光滑滑動(dòng)效果
@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()
// 帶內(nèi)容的固定標(biāo)題
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)
}
// 固定的內(nèi)容
@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) {
// 調(diào)暗文本內(nèi)容
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 - 主要是監(jiān)聽ScrollView的滾動(dòng)
用來監(jiān)聽ScrollView的滾動(dòng) 偏移量的改變文章來源地址http://www.zghlxwxcb.cn/news/detail-720198.html
//
// OffsetModifier.swift
// SpotifyResponvieUI (iOS)
//
// Created by lyh on 2022/8/23.
//
import SwiftUI
// 繼承于 ViewModifier 最主要是能方便擴(kuò)展一些常見的設(shè)置屬性
/*
比如 給Text設(shè)置字體\背景顏色\陰影效果
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())
設(shè)置
*/
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)");
}
}
}
}
}
// 偏好的關(guān)鍵
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模型和樣本數(shù)據(jù)
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"),
]
到了這里,關(guān)于【SwiftUI模塊】0060、SwiftUI基于Firebase搭建一個(gè)類似InstagramApp 2/7部分-搭建TabBar的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!