1. AppStorage 数据简单存储的实现
/// 应用程序数据简单存储
struct AppStorageBootcamp: View {
//@State var currentUserName: String?
@AppStorage("name") var currentUserName: String?
var body: some View {
VStack(spacing: 20) {
Text(currentUserName ?? "Add Name Here")
if let name = currentUserName {
Text(name)
}
Button("Save".uppercased()) {
let name:String = "Emily"
currentUserName = name
// 用户默认值
//UserDefaults.standard.set(name, forKey: "name")
}
}
// .onAppear {
// currentUserName = UserDefaults.standard.string(forKey: "name")
// }
}
}
2. OnboardingView 引导页的示例
2.1 OnboardingView 引导页的实现
// 引导页 View
struct OnboardingView: View {
// 引导页状态:
/*
0 — 欢迎进入
1 — 添加名字
2 — 添加年龄
3 — 添加性别
*/
@State var onboardingState: Int = 0
let transition: AnyTransition = .asymmetric(
insertion: .move(edge: .trailing),
removal: .move(edge: .leading))
/// 输入名字文本框
@State var name: String = ""
/// 年龄值
@State var age: Double = 50
/// 性别
@State var gender: String = "Male"
// 警告框
@State var alertTitle: String = ""
@State var showAlert: Bool = false
// app 存储
@AppStorage("name") var currentUserName: String?
@AppStorage("age") var currentUserAge: Int?
@AppStorage("gender") var currentUserGender: String?
@AppStorage("signed_in") var currentUserSignedIn: Bool = false
var body: some View {
ZStack{
// content
ZStack{
switch onboardingState{
case 0:
welcomeSection
.transition(transition)
case 1:
addNameSection
.transition(transition)
case 2:
addAgeSection
.transition(transition)
case 3:
addGenderSection
.transition(transition)
default:
RoundedRectangle(cornerRadius: 25)
.foregroundColor(.green)
}
}
// buttons
VStack{
Spacer()
bottomButton
}
.padding(30)
}
.alert(isPresented: $showAlert) {
return Alert(title: Text(alertTitle))
}
}
}
struct OnboardingView_Previews: PreviewProvider {
static var previews: some View {
OnboardingView()
.background(Color.purple)
}
}
// MARK: COMPONENTS 扩展类
extension OnboardingView{
/// 登录按钮
private var bottomButton: some View{
Text(onboardingState == 0 ? "SIGN UP" :
onboardingState == 3 ? "FINISH" :
"NEXT")
.font(.headline)
.foregroundColor(.purple)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(10)
.animation(nil) //去掉按钮动画
.onTapGesture {
handleNextButtonPressed()
}
}
/// 欢迎页
private var welcomeSection: some View{
VStack(spacing: 40) {
Spacer()
Image(systemName: "heart.text.square.fill")
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
.foregroundColor(.white)
Text("Find your match.")
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(.white)
.overlay(
Capsule(style: .continuous)
.frame(height: 3)
.offset(y: 5)
.foregroundColor(.white)
, alignment: .bottom
)
Text("This is the #1 app for finding your match online! In this tutotial, we are practicing using AppStorage and Swift UI techniques.")
.foregroundColor(.white)
.fontWeight(.medium)
Spacer()
Spacer()
}
.multilineTextAlignment(.center)
.padding(30)
}
/// 添加名字
private var addNameSection: some View{
VStack(spacing: 20) {
Spacer()
Text("What's your name?")
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(.white)
TextField("Your name here...", text: $name)
.font(.headline)
.frame(height: 55)
.padding(.horizontal)
.background(Color.white)
.cornerRadius(10)
Spacer()
Spacer()
}
.padding(30)
}
/// 添加年龄
private var addAgeSection: some View{
VStack(spacing: 20) {
Spacer()
Text("What's your age?")
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(.white)
Text("\(String(format: "%.0f", age))")
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(.white)
Slider(value: $age, in: 18...100, step: 1)
.accentColor(.white)
Spacer()
Spacer()
}
.padding(30)
}
/// 添加性别
private var addGenderSection: some View{
VStack(spacing: 20) {
Spacer()
Text("What's your gender?")
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(.white)
Picker(selection: $gender) {
Text("Male").tag("Male")
Text("Female").tag("Female")
Text("Non-Binary").tag("Non-Binary")
} label: {
Text(gender.count > 1 ? gender : "Select a gender")
.font(.headline)
.foregroundColor(.purple)
.frame(height: 55)
.frame(maxWidth: .infinity)
.cornerRadius(10)
}
.pickerStyle(.menu)
.accentColor(.white)
Spacer()
Spacer()
}
.padding(30)
}
}
// MARK: FUNCTIONS
extension OnboardingView{
func handleNextButtonPressed(){
// CHECK INPUTS
switch onboardingState{
case 1:
guard name.count >= 3 else{
showAlert(title: "你的名字必须要有3个字符的长度!😩")
return
}
case 3:
guard gender.count > 1 else{
showAlert(title: "请在下一步之前选择一个性别!😳")
return
}
default:
break
}
// GO TO NEXT SECTION
if onboardingState == 3{
// sign in
signIn()
}else{
// spring 弹簧
withAnimation(.spring()) {
onboardingState += 1
}
}
}
// 登录
func signIn(){
currentUserName = name
currentUserAge = Int(age)
currentUserGender = gender
// 添加动画
withAnimation(.spring()) {
currentUserSignedIn = true
}
}
/// 输出警告框
func showAlert(title: String){
alertTitle = title
showAlert.toggle()
}
}
2.2 ProfileView 信息页的实现
/// 信息页 View
struct ProfileView: View {
// app 存储
@AppStorage("name") var currentUserName: String?
@AppStorage("age") var currentUserAge: Int?
@AppStorage("gender") var currentUserGender: String?
@AppStorage("signed_in") var currentUserSignedIn: Bool = false
var body: some View {
VStack(spacing: 10){
Image(systemName: "person.circle.fill")
.resizable()
.scaledToFit()
.frame(width: 150, height: 150)
Text(currentUserName ?? "Your name here")
Text("This user is \(currentUserAge ?? 0) years old")
Text("Their gender is \(currentUserGender ?? "unknown")")
Text("SIGN OUT")
.foregroundColor(.white)
.font(.headline)
.frame(height: 55)
.frame(maxWidth: .infinity)
.background(Color.black)
.cornerRadius(10)
.onTapGesture {
signOut()
}
}
.font(.title)
.foregroundColor(.purple)
.padding()
.padding(.vertical)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 10)
}
/// 退出
func signOut(){
currentUserName = nil
currentUserAge = nil
currentUserGender = nil
withAnimation(.spring()){
currentUserSignedIn = false
}
}
}
2.3 IntroView 简介视图
/// 简介视图
struct IntroView: View {
@AppStorage("signed_in") var currentUserSignedIn: Bool = false
var body: some View {
ZStack{
// background
RadialGradient(
gradient: Gradient(colors: [Color(#colorLiteral(red: 0.8446564078, green: 0.5145705342, blue: 1, alpha: 1)),Color(#colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1))]),
center: .topLeading,
startRadius: 5, // 开始半径
endRadius: UIScreen.main.bounds.height) // 结束半径
.ignoresSafeArea()
if currentUserSignedIn {
// 显示详情页
ProfileView()
// 添加动画
.transition(.asymmetric(insertion: .move(edge: .bottom), removal: .move(edge: .top)))
}else{
// 登记页
OnboardingView()
// 添加动画
.transition(.asymmetric(insertion: .move(edge: .top), removal: .move(edge: .bottom)))
}
// 用户是否已经登录
// 显示个人资料视图
// 否则
// 填写引导视图
}
}
}
2.4 效果图: