swiftui - 从多个图层制作收藏按钮并使用 EnvironmentObject 绑定两个列表
问题描述
通过在我的歌曲应用程序上添加收藏夹,我被困了好几天。在这里,我想在我的歌曲列表中添加一个收藏按钮。我希望我最喜欢的按钮对应于父视图和详细视图。例如,如果我在父视图中将我的一首歌曲标记为(心形按钮)为收藏,我还想在我的详细视图中显示该歌曲被标记为收藏。如果我再次从我的详细视图中按下最喜欢的按钮(这将变得不喜欢),我还想表明我父母的视图中也禁用了最喜欢的歌曲。所以有两个按钮可以控制歌曲是喜欢还是不喜欢。根据我的基本理解,我需要使用 EnvironmentObject 来绑定父视图和子(或细节)视图,因为这两个视图都分为三到四个视图层。根据我的代码,每次我点击收藏夹时,所有歌曲都被选中收藏,我不明白如何在这两个视图之间传递数据。我在下面编写了所有代码用于测试目的。它们有点乱,但我希望它们是可测试的。提前致谢。
import Foundation
import SwiftUI
struct Lyric: Identifiable {
let id = UUID()
let number: Int
var zoTitle: String
let engTitle: String
let key: String
let musicStyle: String
let translation: String
let verse1: String
var verse2: String?
var verse3: String?
var verse4: String?
var verse5: String?
var preChorus: String?
var chorus: String?
var bridge: String?
var isFavoriteSong: Bool
let isNotedSong: Bool
let isHighlightedSong: Bool
let isBookMarkedSong: Bool
let isSharedSong: Bool
let isCopySong: Bool
}
public struct LyricList {
static var hymnLa = [
Lyric(number: 1,
zoTitle: "Pasian Phatna",
engTitle: "Praise God, from whom All Blessings Flow",
key: "Key: G",
musicStyle: "",
translation: "S.S. 9",
verse1: "Thupha kheempeuh hong pia Pasian\nPhat un, leitung mi khempeuh aw, \nPhat un vantung mi honpi'n zong; \nPhat un Pa, Ta le Kha Siangtho.",
isFavoriteSong: false,
isNotedSong: false,
isHighlightedSong: false,
isBookMarkedSong: false,
isSharedSong: false,
isCopySong: false),
Lyric(number: 2,
zoTitle: "Itna Kumpi, Ka Tuu-Cing Pa",
engTitle: "The King of Love My Shephaerd Is (Dominus Regit Me)",
key: "Key: G",
musicStyle: "",
translation: "C.W. 169, S.H. 250",
verse1: "Itna Kumpi, ka tuu-cing pa, \nAma hoih na sia ngei lo, \nA mi suak leng sapna om lo, \nTawntung Ama mi hi ta.",
verse2: "Nuntakna tui a luanna ah, \nTat khiatsa ka kha tonpih, \nLo no naah hong paipih hi, \nVantung an tawh hong vaak hi.",
verse3: "Khuamial sihna kuam sung lau lo, \nKei kiang Topa Na om hi, \nKa lung nuam sak, Na ciangkhut in, \nLam hong hilh singlamteh in.",
verse4: "Ni sim tawntung kizom sual in, \nNa hoihna kipelh ngei lo, \nTuucing siampa, Nang kong phat hi, \nTawntung nangma innpi sung Amen.",
isFavoriteSong: false,
isNotedSong: false,
isHighlightedSong: false,
isBookMarkedSong: false,
isSharedSong: false,
isCopySong: false),
Lyric(number: 3,
zoTitle: "Kumpipa Bia Un",
engTitle: "O Worship the King",
key: "Key: G",
musicStyle: "",
translation: "S.H. 4",
verse1: "Vantung zahtak huai Kumpipa bia un. \nA vaanglian leh hong itna la sa un; \nA hong liah hong keem hong uk tawntung maangpi \nA vaan-lian hi, ci in phat huai Topa hi.",
verse2: "Hongit hong hehpihna van pan taang-a \nA vaang liat-na thu la in sa unla \nA heh ciangin kek-kia tawh kibang ding hi. \nA thu khen-na in haksa mahmah ding hi.",
verse3: "Na lamdang tawh a dim leitung in-ah \nVaanglian tawntung tawh Pasian a hong piang. \nPel ngei lo na hanciamna tawh a kip hi. \nPuan bangin a kiim-kot tuipi hi sak hi.",
verse4: "Naupang bangin thanem leivui tate, \nNang sung ah muan'na bukna kong mu diam; \nNong hehpihna kicing a tawpdong inah, \nHong bawl pa, hong dal pa, hong gum pa i Lawm.",
isFavoriteSong: false,
isNotedSong: false,
isHighlightedSong: false,
isBookMarkedSong: false,
isSharedSong: false,
isCopySong: false),
Lyric(number: 4,
zoTitle: "Pa Tung Min Than'na Om Hen",
engTitle: "Gloria Patri (1st Tune)",
key: "Key: A",
musicStyle: "",
translation: "C.W. 614",
verse1: "Pa tung min than'na om hen, \nTapa tung leh Kha Siangtho tung ah zong, \nPiancil lai leh tu-hun bang-in, \nA tawntung in hih leitung om den ding hi. \nAmen Amen.",
isFavoriteSong: false,
isNotedSong: false,
isHighlightedSong: false,
isBookMarkedSong: false,
isSharedSong: false,
isCopySong: false),
Lyric(number: 5,
zoTitle: "Pa Tung Min Than'na Om Hen",
engTitle: "Gloria Patri (2nd Tune)",
key: "Key: F",
musicStyle: "",
translation: "C.W. 613",
verse1: "Pa tung min than'na om hen, \nTapa tung leh Kha Siangtho tung ah zong, \nPiancil lai leh tu-hun bang-in, \nA tawntung in hih leitung om den ding hi. \nAmen Amen.",
isFavoriteSong: false,
isNotedSong: false,
isHighlightedSong: false,
isBookMarkedSong: false,
isSharedSong: false,
isCopySong: false)
]
}
import Foundation
import SwiftUI
class TapToggle: ObservableObject {
@Published var songLyrics: [Lyric] = LyricList.hymnLa
@Published var shouldShowFavorites: Bool = false
// Hymn
@Published var isHymnSearchTappped: Bool = false
@Published var isFavorite: Bool = false
}
struct Hymn: View {
@AppStorage("darkModeOn") private var darkModeOn: Bool = false
var body: some View {
VStack {
ZStack {
HymnLyrics()
HymnTabView()
}
}
}
}
}
struct Hymn_Previews: PreviewProvider {
static var previews: some View {
Hymn().environmentObject(TapToggle())
}
}
struct HymnTabView: View {
@EnvironmentObject var tappingSwitches: TapToggle
var body: some View {
VStack(spacing: 0) {
Spacer()
HStack {
Spacer()
Group {
Spacer()
Button(action: {
withAnimation {
self.tappingSwitches.shouldShowFavorites = true
}
}, label: {
Image(systemName: "suit.heart")
.font(.system(size: 24, weight: .bold))
})
.fullScreenCover(isPresented: $tappingSwitches.shouldShowFavorites, content: {
HymnFavoriteView(isPresented: $tappingSwitches.shouldShowFavorites)
})
Spacer()
}
Spacer()
}
.foregroundColor(Color("cTextColor"))
.padding(.vertical, 5.0)
.background(Color("cTabColor"))
.clipShape(Capsule())
.padding(.horizontal)
}
}
}
struct HymnLyrics: View {
@EnvironmentObject var tap: TapToggle
var body: some View {
NavigationView {
ScrollView (.vertical, showsIndicators: false) {
LazyVStack(spacing: 5) {
ForEach (tap.songLyrics, id: \.id) { lyric in
MainLyricView(lyric: lyric)
Divider()
.padding(.all)
}
}
}
.navigationBarHidden(true)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct MainLyricView: View {
@State var lyric: Lyric
@EnvironmentObject var tap: TapToggle
@State var selectedFavoriteSong: Bool = false
var body: some View {
Group {
Group {
HStack {
Button(action: {
self.tap.isFavorite.toggle()
}, label: {
if tap.isFavorite {
Image(systemName: "suit.heart.fill")
.foregroundColor(.red)
.padding(.horizontal)
} else {
Image(systemName: "suit.heart")
.padding(.horizontal)
}
})
Spacer()
Text("\(lyric.number)")
Spacer()
}
.padding(.top)
VStack {
Text(lyric.zoTitle)
.font(.title2.smallCaps())
.fontWeight(.bold)
.foregroundColor(.primary)
Text(lyric.engTitle/*.capitalized*/)
.font(.title3)
.fontWeight(.medium)
.foregroundColor(.secondary)
.italic()
}
.padding(.horizontal)
.multilineTextAlignment(.center)
HStack {
Text(lyric.key)
.italic()
Spacer()
Text(lyric.musicStyle)
}
.foregroundColor(.blue)
.padding(.all)
}
}
}
}
struct TitleDetailView: View {
@State var lyric: Lyric
@EnvironmentObject var tap: TapToggle
var body: some View {
Group {
Group {
HStack {
Button(action: {
self.tap.isFavorite.toggle()
}, label: {
if tap.isFavorite {
Image(systemName: "suit.heart.fill")
.foregroundColor(.red)
.padding(.horizontal)
} else {
Image(systemName: "suit.heart")
.padding(.horizontal)
}
})
Spacer()
Text("\(lyric.number)")
Spacer()
}
.padding(.top)
VStack {
Text(lyric.zoTitle)
.font(.title2.smallCaps())
.fontWeight(.bold)
.foregroundColor(.primary)
Text(lyric.engTitle/*.capitalized*/)
.font(.title3)
.fontWeight(.medium)
.foregroundColor(.secondary)
.italic()
}
.padding(.horizontal)
.multilineTextAlignment(.center)
HStack {
Text(lyric.key)
.italic()
Spacer()
Text(lyric.musicStyle)
}
.foregroundColor(.blue)
.padding(.all)
}
}
Spacer()
}
}
struct HymnSearch: View {
@Binding var isPresented: Bool
@State var searchResults: [Lyric] = LyricList.hymnLa
@State private var searchLyrics = ""
@State private var isSearchDelete = false
var body: some View {
NavigationView {
ZStack {
Color("bColor")
.edgesIgnoringSafeArea(.all)
//.shadow(radius: 20)
VStack (alignment: .center, spacing: 10) {
HStack {
HSearchHome(searchLyrics: $searchLyrics, isSearchDelete: $isSearchDelete)
Spacer()
Button(action: {
isPresented = false
}, label: {
Image(systemName: "music.note.house")
.imageScale(.large)
.padding(4.0)
})
}
.padding(.top, 5.0)
.padding(.horizontal)
ScrollView (.vertical, showsIndicators: false) {
LazyVStack(alignment: .leading, spacing: 10) {
ForEach (searchResults.filter({"\($0)".range(of: searchLyrics, options: [.numeric, .caseInsensitive]) != nil
}), id: \.id) { searchSongs in
NavigationLink(
destination: TitleDetailView(lyric: searchSongs),
label: {
SearchDetailView(searchSongs: searchSongs, searchLyrics: $searchLyrics)
})
} // The end of ForEach
}.padding(.horizontal)
}
}
.navigationBarHidden(true)
}
}
}
}
struct HSearchHome: View {
@Binding var searchLyrics: String
@Binding var isSearchDelete: Bool
var body: some View {
HStack {
Image (systemName: "magnifyingglass")
.foregroundColor(.blue)
.padding(.leading)
TextField("Search ...", text: $searchLyrics)
.autocapitalization()
.disableAutocorrection(true)
.onTapGesture {
self.isSearchDelete = true
}
if isSearchDelete {
Image (systemName: "xmark.circle.fill")
.foregroundColor(.secondary)
.padding([.top, .bottom, .trailing])
//.background(Color.red)
.onTapGesture {
withAnimation {
searchLyrics = ""
self.isSearchDelete = false
UIApplication.shared.dismissKeyboard()
}
}
}
}
.foregroundColor(.primary)
.font(.title3)
.frame(width: 350, height: 40)
.background(Color("cTabColor"))
.cornerRadius(20)
}
}
extension UIApplication {
func dismissKeyboard() {
sendAction(#selector (UIResponder
.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct SearchDetailView: View {
var searchSongs: Lyric
@Binding var searchLyrics: String
@EnvironmentObject var tap: TapToggle
var body: some View {
ZStack {
Color("cTabColor")
VStack(alignment: .leading, spacing: 0) { // With Lazy, divider not work. Test without Lazy for multiple lyrics
HStack {
Text("\(searchSongs.number)")
.font(.title2)
.foregroundColor(.primary)
.padding()
VStack(alignment: .leading, spacing: 0) {
Text(searchSongs.zoTitle)
.foregroundColor(.primary)
.fontWeight(.bold)
Text(searchSongs.engTitle)
.fontWeight(.medium)
.foregroundColor(.secondary)
.italic()
}
.lineLimit(1)
.minimumScaleFactor(0.5)
}
Divider()
.padding(.horizontal)
}
}
.cornerRadius(20)
}
}
解决方案
推荐阅读
- onedrive - OneDrive FilePicker 适用于个人帐户,但不适用于企业帐户
- cpu - Qemu Sparc64 仿真 - 键盘不起作用(Windows、Ubuntu 主机测试)
- android - 无法在 Flutter 中使用本地 firebase 模拟器
- python - Python Kivy 日志显示“ModuleNotFoundError: No module named 'aioconsole'” - 如何修复?
- python - 子图以在同一轴上显示两个图形
- android - 带有圆角和可滚动内容的 BottomSheetDialogFragment
- bash - 如何在系统上永远运行 bash 脚本作为后台进程?
- android - 使用 ExoPlayer 进行假修剪/剪切
- wpf - 如何知道 WPF 窗口何时在 Windows 中捕捉/取消捕捉?
- r - 过滤 {quantmod} 系列之前和/或之后的不变价格部分