设置页面
代码:
import SwiftUI
class Settings: ObservableObject {
enum AccountBehavior: CaseIterable {
case register, login
}
enum Sorting: CaseIterable {
case id, name, color, favorite
}
@Published var accountBehavior = AccountBehavior.login
@Published var email = ""
@Published var password = ""
@Published var verifyPassword = ""
@Published var showEnglishName = true
@Published var sorting = Sorting.id
@Published var showFavoriteOnly = false
}
//Sorting 的辅助属性
extension Settings.Sorting {
var text: String {
switch self {
case .id: return "ID"
case .name: return "名字"
case .color: return "颜色"
case .favorite: return "最爱"
}
}
}
//AccountBehavior 的辅助属性
extension Settings.AccountBehavior {
var text: String {
switch self {
case .register: return "注册"
case .login: return "登录"
}
}
}
struct SettingView: View {
@ObservedObject var settings = Settings()
var body: some View {
Form(content: {
accountSection
optionSection
actionSection
})
}
///账户组
var accountSection: some View {
Section(header: Text("账户")) {
Picker(selection: $settings.accountBehavior, label: Text(""), content: {
ForEach(Settings.AccountBehavior.allCases, id: \.self) {
Text($0.text)
}
})
.pickerStyle(SegmentedPickerStyle())
TextField("电子邮箱",text: $settings.email)
TextField("密码",text: $settings.password)
if settings.accountBehavior == .register {
SecureField("确认密码",text: $settings.verifyPassword)
}
Button(settings.accountBehavior.text) {
print("登录/注册")
}
}
}
///可选组
var optionSection: some View {
Section(header: Text("选项")) {
Toggle(isOn: $settings.showEnglishName, label: {
Text("显示应为名")
})
Picker(selection: $settings.sorting, label: Text("排序方式"), content: {
ForEach(Settings.Sorting.allCases, id: \.self) {
Text($0.text)
}
})
Toggle(isOn: $settings.showFavoriteOnly, label: {
Text("只显示收藏")
})
}
}
///清除缓存
var actionSection: some View {
Section {
Button(action: {
print("清空缓存")
}, label: {
Text("清空缓存")
.foregroundColor(.red)
})
}
}
}
struct SettingView_Previews: PreviewProvider {
static var previews: some View {
SettingView()
}
}
列表页面:
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)
}
}
弹出框
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))
}
}