VCG211277627289.jpg

设置页面

image.png

代码:

  1. import SwiftUI
  2. class Settings: ObservableObject {
  3. enum AccountBehavior: CaseIterable {
  4. case register, login
  5. }
  6. enum Sorting: CaseIterable {
  7. case id, name, color, favorite
  8. }
  9. @Published var accountBehavior = AccountBehavior.login
  10. @Published var email = ""
  11. @Published var password = ""
  12. @Published var verifyPassword = ""
  13. @Published var showEnglishName = true
  14. @Published var sorting = Sorting.id
  15. @Published var showFavoriteOnly = false
  16. }
  17. //Sorting 的辅助属性
  18. extension Settings.Sorting {
  19. var text: String {
  20. switch self {
  21. case .id: return "ID"
  22. case .name: return "名字"
  23. case .color: return "颜色"
  24. case .favorite: return "最爱"
  25. }
  26. }
  27. }
  28. //AccountBehavior 的辅助属性
  29. extension Settings.AccountBehavior {
  30. var text: String {
  31. switch self {
  32. case .register: return "注册"
  33. case .login: return "登录"
  34. }
  35. }
  36. }
  37. struct SettingView: View {
  38. @ObservedObject var settings = Settings()
  39. var body: some View {
  40. Form(content: {
  41. accountSection
  42. optionSection
  43. actionSection
  44. })
  45. }
  46. ///账户组
  47. var accountSection: some View {
  48. Section(header: Text("账户")) {
  49. Picker(selection: $settings.accountBehavior, label: Text(""), content: {
  50. ForEach(Settings.AccountBehavior.allCases, id: \.self) {
  51. Text($0.text)
  52. }
  53. })
  54. .pickerStyle(SegmentedPickerStyle())
  55. TextField("电子邮箱",text: $settings.email)
  56. TextField("密码",text: $settings.password)
  57. if settings.accountBehavior == .register {
  58. SecureField("确认密码",text: $settings.verifyPassword)
  59. }
  60. Button(settings.accountBehavior.text) {
  61. print("登录/注册")
  62. }
  63. }
  64. }
  65. ///可选组
  66. var optionSection: some View {
  67. Section(header: Text("选项")) {
  68. Toggle(isOn: $settings.showEnglishName, label: {
  69. Text("显示应为名")
  70. })
  71. Picker(selection: $settings.sorting, label: Text("排序方式"), content: {
  72. ForEach(Settings.Sorting.allCases, id: \.self) {
  73. Text($0.text)
  74. }
  75. })
  76. Toggle(isOn: $settings.showFavoriteOnly, label: {
  77. Text("只显示收藏")
  78. })
  79. }
  80. }
  81. ///清除缓存
  82. var actionSection: some View {
  83. Section {
  84. Button(action: {
  85. print("清空缓存")
  86. }, label: {
  87. Text("清空缓存")
  88. .foregroundColor(.red)
  89. })
  90. }
  91. }
  92. }
  93. struct SettingView_Previews: PreviewProvider {
  94. static var previews: some View {
  95. SettingView()
  96. }
  97. }

列表页面:

image.png


import SwiftUI

struct PokemonList: View {

    @State var expandingIndex: Int?

    var body: some View {
        ScrollView(content: {
            ForEach(PokemonViewModel.all) { pokemon in
                PokemonlnfoRow(model: pokemon,
                               expanded: self.expandingIndex == pokemon.id)
                    .onTapGesture {
                        print("weiweiweiweiwei")
                        withAnimation(
                            .spring(
                                response: 0.55,
                                dampingFraction: 0.425,
                                blendDuration: 0
                            )
                        ) {
                            if self.expandingIndex == pokemon.id {
                                self.expandingIndex = nil
                            }else {
                                self.expandingIndex = pokemon.id
                            }
                        }
                    }
            }
        })
    }
}

struct PokemonList_Previews: PreviewProvider {
    static var previews: some View {
        PokemonList()
    }
}

import SwiftUI

struct PokemonlnfoRow: View {

    let model: PokemonViewModel
    let expanded: Bool

    var body: some View {
        //
        VStack {

            HStack {
                Image("Pokemon-\(model.id)")
                    .resizable()
                    .frame(width: 50, height: 50)
                    .aspectRatio(contentMode: .fit)
                    .shadow(radius: 4)
                Spacer()
                VStack(alignment: .trailing, content: {
                    Text(model.name)
                        .font(.title)
                        .fontWeight(.black)
                        .foregroundColor(.white)
                    Text(model.nameEN)
                        .font(.subheadline)
                        .foregroundColor(.white)
                })
            }
            .padding(.top, 12)
            Spacer()
            HStack(spacing: expanded ? 20 : -30 , content: {
                Spacer()
                Button(action: {
                    print("fav")
                }, label: {
                    Image(systemName: "star")
                        .modifier(ToolButtonModifier())
                })
                Button(action: {
                    print("panel")
                }, label: {
                    Image(systemName: "chart.bar")
                        .modifier(ToolButtonModifier())
                })
                Button(action: {
                    print("web")
                }, label: {
                    Image(systemName: "info.circle")
                        .modifier(ToolButtonModifier())
                })
            })
            .padding(.bottom, 12)
            .opacity(expanded ? 1.0 : 0.0)
            .frame(maxHeight: expanded ? .infinity : 0)
        }
        .frame(height:expanded ? 120 : 80)
        //左右边距
        .padding(.leading,23)
        .padding(.trailing,15)
        .background (
            ZStack(content: {
                //加边框
                RoundedRectangle(cornerRadius: 20)
                    .stroke(model.color, style: StrokeStyle(lineWidth: 4))
                //添加渐变色
                RoundedRectangle(cornerRadius: 20)
                    .fill(LinearGradient(
                        gradient: Gradient(colors: [.white,model.color]),
                        startPoint: .leading,
                        endPoint: .trailing
                    ))

            })
        )
        .padding(.horizontal)
    }
}

struct PokemonlnfoRow_Previews: PreviewProvider {
    static var previews: some View {
        VStack(content: {
            PokemonlnfoRow(model: .sample(id: 1), expanded: false)
            PokemonlnfoRow(model: .sample(id: 21), expanded: true)
            PokemonlnfoRow(model: .sample(id: 25), expanded: false)
        })
    }
}

struct ToolButtonModifier: ViewModifier {

    func body(content: Content) -> some View {
        content
            .font(.system(size: 25))
            .foregroundColor(.white)
            .frame(width: 30, height: 30)
    }

}

弹出框

image.png


import SwiftUI

extension PokemonInfoPanel {

    struct Header: View {

        let model: PokemonViewModel
        var body: some View {
            HStack(spacing: 18, content: {
                pokemonIcon
                nameSpecies
                verticalDivider
                VStack(spacing: 12, content: {
                    bodyStatus
                    typeInfo
                })
            })
        }

        ///前面的icon
        var pokemonIcon: some View {
            Image("Pokemon-\(model.id)")
                .resizable()
                .frame(width: 68, height: 68)
        }

        ///名字
        var nameSpecies: some View {
            VStack(spacing: 10, content: {
                VStack(content: {
                    Text(model.name)
                        .font(.system(size: 22))
                        .fontWeight(.bold)
                        .foregroundColor(model.color)

                    Text(model.nameEN)
                        .font(.system(size: 13))
                        .fontWeight(.bold)
                        .foregroundColor(model.color)

                })

                Text(model.genus)
                    .font(.system(size: 13))
                    .fontWeight(.bold)
                    .foregroundColor(.gray)
            })

        }

        ///垂直分割线
        var verticalDivider: some View {
            RoundedRectangle(cornerRadius: 1)
                .frame(width: 1, height: 44)
                .opacity(0.1)
        }

        var bodyStatus: some View {
            VStack(alignment: .leading, content: {
                HStack(content: {
                    Text("身高")
                        .font(.system(size: 11))
                        .foregroundColor(.gray)

                    Text(model.height)
                        .font(.system(size: 11))
                        .foregroundColor(model.color)
                })

                HStack(content: {
                    Text("体重")
                        .font(.system(size: 11))
                        .foregroundColor(model.color)

                    Text(model.weight)
                        .font(.system(size: 11))
                        .foregroundColor(model.color)
                })
            })
        }

        var typeInfo: some View {
            HStack(content: {
                ForEach(self.model.types) { t in
                    ZStack {
                        RoundedRectangle(cornerRadius: 7)
                            .fill(t.color)
                            .frame(width: 36, height: 14)
                        Text(t.name)
                            .font(.system(size: 10))
                            .foregroundColor(.white)
                    }
                }
            })
        }
    }
}

struct PokemonInfoPanelHeader_Previews: PreviewProvider {
    static var previews: some View {
        PokemonInfoPanel.Header(model: .sample(id: 1))
    }
}

import SwiftUI

///技能列表

extension PokemonInfoPanel {

    struct AbilityList: View {

        let model: PokemonViewModel
        let abilityModels: [AbilityViewModel]?

        var body: some View {
            VStack(alignment: .leading, spacing: 12, content: {
                Text("技能")
                    .font(.headline)
                    .fontWeight(.bold)
                if abilityModels != nil {
                    ForEach(abilityModels!) { ability in
                        Text(ability.name)
                            .font(.subheadline)
                            .foregroundColor(self.model.color)
                        Text(ability.descriptionText)
                            .font(.footnote)
                            .foregroundColor(Color(hex: 0xAAAAA))
                            .fixedSize(horizontal: false, vertical: true)
                    }
                }
            })
            .frame(maxWidth: .infinity, alignment: .leading)
        }
    }
}


struct PokemonInfoPanelAbilityList_Previews: PreviewProvider {
    static var previews: some View {
        PokemonInfoPanel(model: .sample(id: 1))
    }
}

import SwiftUI

//面板信息

struct PokemonInfoPanel: View {

    let model: PokemonViewModel
    var abilities: [AbilityViewModel] {
        AbilityViewModel.sample(pokemonID: model.id)
    }

    var topIndicator: some View {
        RoundedRectangle(cornerRadius: 3)
            .frame(width: 40, height: 6)
            .opacity(0.2)
    }

    var pokemonDescription: some View {
        Text(model.descriptionText)
            .font(.callout)
            .foregroundColor(Color(hex: 0x666666))
            .fixedSize(horizontal: false, vertical: true)
    }

    var body: some View {

        VStack(spacing: 20, content: {
            topIndicator
            Header(model: model)
            pokemonDescription
            Divider()
            AbilityList(
                model: model,
                abilityModels: abilities)
        })
        .padding(
            EdgeInsets(
                top: 12,
                leading: 30,
                bottom: 30,
                trailing: 30)
        )
        .blurBackground(style: .systemMaterial)
        //.background(Color.white)
        .cornerRadius(20)
        .fixedSize(horizontal: false, vertical: true)
    }
}


struct PokemonInfoPanel_Previews: PreviewProvider {
    static var previews: some View {
        PokemonInfoPanel(model: .sample(id: 1))
    }
}