全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2022-11-18_元宇宙来了,准备好你的电子名片了吗?(七)

您的位置:首页 >> 新闻 >> 行业资讯

元宇宙来了,准备好你的电子名片了吗?(七) 前提回顾不知不觉已经到了第七章了,在过往每一个章节中,我们都增加和完成项目的一些功能,让Linkwirld这款产品越来越接近完成品。 一款以用户操作为核心功能的产品,需要包含增删改查4部分功能,在之前的章节中我们已经完成了查看、新增、删除的功能,还缺少对于身份卡进行编辑的功能。编辑操作为用户对于之前创建的内容的调整或者更新,在ToDo、Note等应用当中很是常见。 那么在本章中,我们来完成后编辑相关的操作。 功能分析:新增和编辑页面的区别很多时候都会有一个疑惑,现在页面和编辑页面到底有没有区别?开发人员究竟只需要维护一个页面还是要维护两个页面? 一般情况下,由于页面样式的相似性,新增和编辑操作在开发的角度上是需要做到共用的。但新增和编辑页面除了数据绑定外没有太大的样式区分时,我们建议可以将样式或者组件抽离出来,然后再单独应用。 视图复用:创建单独的构件在新增和编辑页面中,我们会发现有几部分视图内容是可以复用的:titleInputView平台输入框、platformPicker平台选择器、indexURLView链接地址。如下图所示: 因此对于这三部分,我们可以将其抽离出来搭建单独的构件,如此便可以在新增页面和编辑页面都可以引用。而且如果需要修改样式,也只需要修改构件的样式,新增和编辑页面的样式就可以统一变化。 我们创建一个新的文件夹,命名为Artifacts,并且创建3个SwiftUI文件,并为其命名为TitleInputView、PlatformPicker、IndexURLView,如下图所示: 我们先来到TitleInputView文件,将原来NewView中的titleInputView视图代码复制过来,如下代码所示: importSwiftUI structTitleInputView:View{ @Bindingvartitle:String varbody:someView{ TextField("请输入头衔",text:$title) .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) .disableAutocorrection(true) .autocapitalization(.none) } } structTitleInputView_Previews:PreviewProvider{ staticvarpreviews:someView{ TitleInputView(title:.constant("")) } } 上述代码中,除了TextField输入框相关代码复制过来,我们还需要完善相关的绑定参数。声明一个用于双向绑定输入框的参数title,并且在TitleInputView预览时给参数赋予默认值。 紧接着来到PlatformPicker视图,将原来NewView中的platformPicker视图代码复制过来,如下代码所示: importSwiftUI structPlatformPicker:View{ @BindingvarplatformIcon:String @BindingvarplatformName:String letplatforms=[ ("稀土掘金技术社区","icon_juejin"), ("CSDN博客","icon_csdn"), ("阿里云社区","icon_aliyun"), ("华为云社区","icon_huaweiyun"), ] vargridItemLayout=[GridItem(.flexible()),GridItem(.flexible()),GridItem(.flexible()),GridItem(.flexible())] varbody:someView{ ScrollView{ LazyVGrid(columns:gridItemLayout,spacing:10){ ForEach(0..platforms.count,id:.self){itemin ifplatforms[item].0==platformName{ Image(platforms[item].1) .resizable() .aspectRatio(contentMode:.fit) .frame(width:48,height:48) .clipShape(Circle()) .overlay( Circle() .stroke(Color.green,lineWidth:4) ) }else{ Image(platforms[item].1) .resizable() .aspectRatio(contentMode:.fit) .frame(width:48,height:48) .clipShape(Circle()) .onTapGesture{ platformIcon=platforms[item].1 platformName=platforms[item].0 } } } } } .padding() .background(Color(.systemGray6)) .cornerRadius(8) .padding(.horizontal) .frame(maxHeight:140) } } structPlatformPicker_Previews:PreviewProvider{ staticvarpreviews:someView{ PlatformPicker(platformIcon:.constant("icon_juejin"),platformName:.constant("稀土掘金技术社区")) } } 上述代码中,我们仍旧讲需要声明双向绑定的变量,如:platformIcon平台图标、platformName平台名称,值得注意的是,原有我们声明的selectedItem完全可以换成判断platformName是否等于点击的名称,减少一个参数。如下代码所示: platforms[item].0==platformName 声明双向绑定变量还需要在预览PlatformPicker时增加参数的默认值,如下代码所示: PlatformPicker(platformIcon:.constant("icon_juejin"),platformName:.constant("稀土掘金技术社区")) 下一步到IndexURLView视图,将原来NewView中的indexURLView视图代码复制过来,如下代码所示: importSwiftUI structIndexURLView:View{ @BindingvarindexURL:String varbody:someView{ ZStack(alignment:.topLeading){ TextEditor(text:$indexURL) .font(.system(size:17)) .padding(15) .disableAutocorrection(true) .autocapitalization(.none) ifindexURL.isEmpty{ Text("请输入主页链接") .foregroundColor(Color(UIColor.placeholderText)) .padding(20) } } .background(Color(.systemGray6)) .cornerRadius(8) .padding() .frame(maxHeight:240) } } structIndexURLView_Previews:PreviewProvider{ staticvarpreviews:someView{ IndexURLView(indexURL:.constant("")) } } 完成之后,我们就可以回到NewView视图中,将原来的参数以及titleInputView平台输入框视图、platformPicker平台选择器视图、indexURLView链接地址视图的代码删掉,如下图所示: 删除代码后,我们使用单独搭建的构件来重新搭建样式,如下代码所示: TitleInputView(title:$title) PlatformPicker(platformIcon:$platformIcon,platformName:$platformName) IndexURLView(indexURL:$indexURL) 如此,NewView视图在维持原有功能样式不变的情况下,代码量也精简很多。 界面设计:创建EditView编辑页面完成单独的构件后,我们就可以来完成编辑页面的设计。创建一个新的SwiftUI文件,命名为EditView,如下图所示: 我们先搭建基础的样式,示例:顶部导航菜单、页面标题、关闭按钮等等,如下图所示: importSwiftUI structEditView:View{ @Environment(.presentationMode)varpresentationMode varbody:someView{ NavigationStack{ Text("Hello,World!") .navigationBarTitle("编辑身份卡",displayMode:.inline) .navigationBarItems(trailing:closeBtn()) } } //关闭按钮 funccloseBtn()-someView{ Button(action:{ self.presentationMode.wrappedValue.dismiss() }){ Image(systemName:"xmark.circle.fill") .font(.system(size:17)) .foregroundColor(.gray) } } } 上述代码中,我们基本和NewView页面的设计一样,使用NavigationStack搭建顶部导航菜单,并使用navigationBarTitle修饰符设置导航标题,使用navigationBarItems修饰符设置关闭页面按钮,并通过声明全局变量presentationMode和搭建单独的关闭按钮closeBtn来实现关闭编辑页面。 对于编辑保存按钮,样式和操作和NewView页面可能不一样,我们也单独构建按钮,如下代码所示: //编辑更新按钮 funcupdateBtn()-someView{ Button(action:{ self.presentationMode.wrappedValue.dismiss() }){ Text("确定更新") .font(.system(size:17)) .foregroundColor(.white) .bold() .padding() .frame(maxWidth:.infinity) .background(Color.blue) .cornerRadius(8) .padding(.horizontal) } } 完成后将编辑按钮updateBtn添加到EditView编辑页面视图中,如下代码所示: VStack(spacing:15){ updateBtn() } 在引用构件之前,我们先来理解下数据关系。 EditView编辑页面和ContentView主页的数据关系是,用户在ContentView主页点击单张身份卡片,然后打开EditView编辑页面,并将ContentView主页身份卡片的数据传递到EditView编辑页面。 我们可以声明一个符合Model数据模型的参数,然后无论是TitleInputView、PlatformPicker、IndexURLView的参数都绑定Model数据模型的参数,然后该数据模型双向绑定到ContentView主页中,就可以将ContentView主页的数据传递过来,如下代码所示: @Statevarmodel:Model 然后调用TitleInputView、PlatformPicker、IndexURLView构件,并且绑定model模型的值,如下代码所示: VStack(spacing:15){ TitleInputView(title:$model.title) PlatformPicker(platformIcon:$model.platformIcon,platformName:$model.platformName) IndexURLView(indexURL:$model.indexURL) updateBtn() Spacer() } 交互动作:打开EditView编辑页面完成后,我们回到ContentView主页中,我们来实现页面跳转的逻辑。首先我们先声明一个用于页面跳转的参数,如下代码所示: @StatevarshowEditView:Bool=false 然后在CardView视图中增加页面跳转的方法,这里也可以使用Sheet修饰符,如下代码所示: //打开编辑弹窗 .sheet(isPresented:self.$showEditView,onDismiss:{self.showEditView=false}){ EditView(model:self.item??Model(platformIcon:"",title:"",platformName:"",indexURL:"")) } 上述代码中,我们使用sheet修饰符用户打开模态弹窗,触发操作绑定声明好的变量showEditView,打开的模态弹窗的页面为EditView编辑页面。 由于EditView编辑页面需要传入参数,这里我们选择传入的对应model的参数为声明的item,当item不存在时,则默认传入一个符合Model格式的数据,避免报错。 对于编辑操作,我们可以给CardView增加多一个指示符,告知用户这个卡片是可以被编辑的,如下代码所示: Image(systemName:"ellipsis") .padding() .foregroundColor(.black) .gesture( TapGesture() .onEnded({ self.showEditView.toggle() }) ) 上述代码中,我们增加了一个Image图片到CardView视图中,当点击这个Image图片时,打开EditView编辑页面。 考虑到在ContentView我们已经使用NavigationLink顶部导航菜单进行跳转,那么如果我们给按钮增加点击事件,会存在两个点击事件冲突的情况。 我们先注释掉NavigationLink相关的代码,如下图所示: 完成后,我们点击刚刚创建的编辑按钮,预览下效果,如下图所示: 新增功能:编辑并更新内容完成样式后,我们来实现下编辑更新的逻辑,来到ViewModel视图模型中,我们创建一个编辑并更新的方法,如下图所示: //编辑更新数据项 funceditItem(item:Model){ ifletid=models.firstIndex(where:{$0.id==item.id}){ models[id]=item } } 编辑操作很简单,首先要找到点击编辑的数据项的ID在整个models数据集中的位置,更新后将更新内容赋予当前的ID,便实现了编辑更新操作。 回到EditView视图中,先引入ViewModel视图模型,如下代码所示: varviewModel:ViewModel 然后在EditView视图预览时,给声明的viewModel赋予默认值,如下代码所示: EditView(model:Model(platformIcon:"",title:"",platformName:"",indexURL:""),viewModel:ViewModel()) 由于我们在EditView视图声明了变量viewModel,因此在使用EditView视图的页面也要进行参数绑定。 我们来到ContentView文件,在CardView视图中,需要补充viewModel相关的参数,如下图所示: 绑定完成后,我们再回到EditView视图,在点击updateBtn更新按钮时,调用ViewModel视图模型中的editItem方法,如下代码所示: self.viewModel.editItem(item:model) 如此,我们便实现了编辑更新的方法。 交互动作:打开HonePageView页面完成打卡编辑弹窗,并实现编辑更新操作后,我们来补充完善下打开HonePageView页面的交互。在之前的章节我们使用NavigationLink导航菜单跳转方式实现了页面跳转,由于会和我们点击编辑操作相冲突,因此我们注释了这部分代码。 这里我们再介绍一种弹窗,fullScreenCover全屏覆盖弹窗,用fullScreenCover也可以实现页面跳转的效果。 首先先声明打开弹窗的变量,我们在CardView视图中声明变量,如下代码所示: @StatevarshowHomePageView:Bool=false 然后实现调用fullScreenCover全屏覆盖弹窗的方法,如下代码所示: //打开身份卡主页 .fullScreenCover(isPresented:$showHomePageView,content:{ HomePageView(platformName:platformName,indexURL:indexURL) .edgesIgnoringSafeArea(.all) }) 上述代码中,我们给CardView的主要内容增加了fullScreenCover修饰符,用于打开全屏覆盖弹窗。 弹窗打开触发动作绑定声明好的参数showHomePageView,目标地址选择HomePageView,并且绑定相关的参数,我们希望这个弹窗全屏展示,增加了edgesIgnoringSafeArea忽略安全区域修饰符。 打开弹窗的操作,我们希望点击身份卡片时打开,但又不能和编辑按钮相冲突。 我们可以将平台图标、平台称号、平台名称部分的样式再使用一个容器包裹起来,点击这个容器打开HomePageView页面,这样就可以做到不和编辑按钮相冲突了。如下图所示: 最后我们增加点击事件在这个容器中,当点击时打开fullScreenCover弹窗,如下代码所示: .gesture( TapGesture() .onEnded({ self.showHomePageView.toggle() }) ) 由于fullScreenCover弹窗是由下往上打开,因此我们可以换一个返回按钮的样式,让操作看起来流畅些,如下图所示: 项目小结在本章中,我们实现了EditView页面的界面设计、页面跳转、编辑更新方法,单一个编辑操作就很不容易,哭泣。 但最重要的是学习了结构化编程方法,将页面的元素分块,然后抽离创建单独的构件,如此不管在新增页面还是在编辑页面,我们都只需要维护一套代码,这大大减轻了代码量,也使得编程更加优雅。 那么对于一个本地项目来说,linkworld已经完成了查看、新增、编辑、删除操作,似乎可以告一段落了。但是,如果一款产品要成功上线AppStore,那么仅仅在模拟器中使用这些功能是远远不够的,我们还需要进行本地化存储等功能的开发等等工作。 那么在下一章中,我们将介绍如果实现本地存储及远端数据存储相关的内容,请保持期待吧~ 版权声明本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究! 阅读原文

上一篇:2021-09-30_百亿参数、中文NLU能力首次超越人类,QQ浏览器大模型「神舟」登顶CLUE 下一篇:2025-09-05_沉寂一个月,openPangu性能飙升8%!华为1B开源模型来了

TAG标签:

20
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价