AppStorage, OnboardingView 的示例

news2024/11/24 12:26:42

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 效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/749104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ghostscript开源PDF库中发现关键漏洞

在Linux中广泛使用的PostScript语言和PDF文件开源解释器Ghostscript被发现存在严重远程代码执行漏洞。 该漏洞被标记为CVE-2023-3664,CVSS v3评级为9.8,影响10.01.2之前的所有Ghostscript版本,10.01.2是三周前发布的最新版本。 据Kroll公司…

深入理解netfilter和iptables

目录 Netfilter的设计与实现 内核数据包处理流 netfilter钩子 钩子触发点 NF_HOOK宏与Netfilter裁定 回调函数与优先级 iptables 内核空间模块 xt_table的初始化 ipt_do_table() 复杂度与更新延时 用户态的表,链与规则 conntrack Netfilter(结合iptable…

基于C语言设计的足球信息查询系统

完整资料进入【数字空间】查看——baidu搜索"writebug" 需求分析与概要设计 2.1 项目说明 我们小组的选题主要是面向足球爱好者,在普通社交软件的基础之上,围绕足球的主题展开设计,以便于他们能够更好的交流相关的话题&#xff…

高效编程的捷径:HbuilderX的独特之处

目录 引言HbuilderX的功能HbuilderX的优点HbuilderX的缺点总结 HBuilderX 官网 引言 在当今科技发展日新月异的时代,软件开发已成为一个极富挑战性且高需求的领域。为了在竞争激烈的市场中脱颖而出,程序员们需要掌握一系列高效编程的技巧和工具。在这个过…

谈一谈LLM在推荐域的一些理解

作者:陈祖龙(葬青) 一、前言 最近大模型真的很火,从个人到公司,各行各业都在学习大模型、总结大模型和尝试应用大模型。大模型其实不是一个新的产物,已经在NLP发展了很多年。ChatGPT的诞生,经验的效果震惊了所有人&…

ES系列--es初探

一、前言 一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进 行全文检索需要扫描整个表,如果数据量大的话即使对 SQL 的语法优化,也收效甚微。建 立了索引,但是维护起来也很麻烦&#xff0…

人工智能-电脑如何像人一样思考?

发展历史 在电影如 终结者、机械公敌 中,机器人为什么能够像人一样思考?其实这就是人工智能。人工智能多方面:例如人脸识别系统、肺部影响CT,手机中的美颜、垃圾邮件拦截、自动驾驶 。 上世纪30-50年代,随着计算机科…

服务器如何查库磁盘情况?

查库磁盘情况 du -h --max-depth1 ./ | sort -hr

九九乘法表案例

for循环嵌套 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</titl…

Linux5.15 Zookeeper集群 + Fafka集群

文章目录 计算机系统5G云计算第四章 LINUX Zookeeper集群 Fafka集群一、Zookeeper1.Zookeeper 概述1&#xff09;Zookeeper 定义2&#xff09;Zookeeper 工作机制3&#xff09;Zookeeper 特点4&#xff09;Zookeeper 数据结构5&#xff09;Zookeeper 应用场景6&#xff09;Zoo…

unittest与pytest自动化测试框架

引言 前面一篇文章已经介绍了python单元测试框架&#xff0c;大家平时经常使用的是unittest&#xff0c;因为它比较基础&#xff0c;并且可以进行二次开发&#xff0c;如果你的开发水平很高&#xff0c;集成开发自动化测试平台也是可以的。而这篇文章主要讲unittest与pytest的区…

大华相机接入web页面实现人脸识别

先看下效果&#xff0c;中间主视频流就是大华相机&#xff08;视频编码H.264&#xff09;&#xff0c;海康相机&#xff08;视屏编码H.265&#xff09; 前端接入视屏流代码 <!--视频流--><div id"col2"><div class"cell" style"flex: …

2023夏季营销报告新鲜出炉!(小红书平台)

夏季温度持续走高&#xff0c;大众需求也在升级。品牌如何借势和部署相关内容&#xff1f; 本期&#xff0c;千瓜推出《千瓜2023夏季营销策略数据报告&#xff08;小红书平台》&#xff08;本文非完整版报告&#xff09;&#xff0c;围绕七大行业&#xff08;美妆|个护|食品|家…

能翻译维吾尔语的软件有哪些?这几个可以用用看

能翻译维吾尔语的软件有哪些&#xff1f;在如今全球化的背景下&#xff0c;不同语言之间的沟通交流变得尤为重要。维吾尔语作为中国特有的少数民族语言之一&#xff0c;它的翻译需求日益增长。本文将介绍几款精选的维吾尔语翻译软件&#xff0c;帮助大家顺利实现跨语言沟通。 智…

creator 滑动循环展示图片 自动展示

import MyBaseView from "./MyBaseView";const { ccclass, property } cc._decorator;ccclass export default class ScrollCard extends MyBaseView {property({ tooltip: "是否自动展示" })Move_zidong: boolean true;property({ tooltip: "自动展…

【机器学习】特征降维 - 方差选择法VarianceThreshold

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 方差选择法 一、方差科普二、方差选择API三、获取数…

炎炎夏日,相约Polkadot Decoded 2023上海

​上周&#xff0c;Moonbeam现身胡志明&#xff0c;参与GM Vietnam峰会活动&#xff0c;并与Chainlink和AWS等知名公司的代表一同畅谈Web3。 这周&#xff0c;Moonbeam中文社区将出席Polkadot未来论坛上海站&#xff0c;与来自波卡生态中不同平行链的代表一同探讨波卡新一代生…

小区物业管理系统需求分析

小区物业管理系统核心在于加强管理&#xff0c;提升效率&#xff0c;降低成本。实现物业核心业务信息化&#xff0c;为员工提供流畅运营模式&#xff0c;为业主提供高品质服务&#xff0c;有助于公司做强做大&#xff0c;系统优势主要有以下几方面&#xff1a; • 服务数字化&a…

Systemd服务单元

Systemd服务单元 service服务文件基本格式自定义service文件systemctl定时重启service文件中的type systemctl管理service查看服务状态查看服务是否运行查看服务是否被启用 查看开机自启服务列表设置开机启动开机启动的原理&#xff1a; 取消开机启动启动/暂停/重启服务重新加载…

day04 重新学python——数据容器

文章目录 一、数据容器1.数据容器&#xff1a;list(列表)2.list(列表)的遍历3.数据容器&#xff1a;tuple(元组)4.数据容器&#xff1a;str(字符串)5.数据容器的切片6.数据容器&#xff1a;set(集合)7.数据容器&#xff1a;dict(字典、映射)8.数据容器的通用操作 一、数据容器 …