置顶
菜鸟入门,各位大佬轻喷,如有谬误之处欢迎讨论建议,也欢迎各位道友与我同行
“不积跬步,无以至千里;不积小流,无以成江海”
继续
上文中我们引入了第三方库Popup,所以本文我们来讨论Popup的封装,实现一个全局Toast的功能
效果如下:在这里插入图片描述
期望的调用方式如下:
showToast("测试");hideToast();
思考
按照上文的调用方式描述,很显然我们不希望这几个方法被定义在本身的视图上,一定是在另一个文件中定义好,这里可以直接使用
所以我们将会用到extension
同样的我们也不希望这个封装会大量地放到某一个视图中去,最好是直接在封装的地方就能做完,同时在原来的页面视图中只需要进行调用即可,最好是直接在初始化的时候用一次即可。
所以我们将会用到ViewModifier
结合之前我们用到的
AppStorage,完全可以实现一个全局的Toast实现
我们新增一个文件:Toast.swift用来存放所有的对Toast的封装,内容如下:
importSwiftUIimportExytePopupView///extension顾名思义即扩展///extension可以给指定的对象、类型、struct、protocol等扩展func,不用再在具体的结构里面显式声明方法///很好的一个横向解耦方式,很像PHP中的Trait///假如以后有相同方法的两个view,我们完全可以抽象到一起extensionView{//初始化启动Toast返回一个someViewpublicfuncenableToast()-someView{
AppStorage("showGlobalToast")varshowGlboalToast:Bool=false;AppStorage("globalToastText")varglobalToastText:String="";//这里将全局变量重置,以避免正好在显示Toast的时候退出了app//导致下次打开app的时候就有一个ToastshowGlboalToast=falseglobalToastText=""//这里调用了一个viewmodifierreturnself.modifier(initToast())}//显示一个Toast,传入内容publicfuncshowToast(content:String){AppStorage("showGlobalToast")varshowGlboalToast:Bool=false;AppStorage("globalToastText")varglobalToastText:String="";//修改全局变量showGlboalToast=true;globalToastText=content;}}///viewmodifier相当于在外面修改某个视图的结构///body方法中提供了一个content就是调用你的那个视图///你也可以理解为这是在跳转页面,但是把原始页面的实例给你了structinitToast:ViewModifier{AppStorage("showGlobalToast")varshowGlboalToast:Bool=false;AppStorage("globalToastText")varglobalToastText:String="";publicfuncbody(content:Content)-someView{//直接给content调用popupcontent.popup(isPresented:$showGlboalToast,type:.default,position:.bottom,animation:.easeOut(duration:0),autohideIn:2,dragToDismiss:false,closeOnTap:false,closeOnTapOutside:true,backgroundColor:.clear){Text(globalToastText).frame(width:,height:80).background(.gray).foregroundColor(.white).cornerRadius(20.0)}}}整个的封装过程就结束
接下来就是调用部分
修改helloworldApp.swift,即你的APP入口文件
importSwiftUI
mainstructhelloworldApp:App{varbody:someScene{WindowGroup{IndexView()//调用封装中扩展的方法即可.enableToast()}}}在新增todo的按钮上进行调用
Button("添加"){//这里可以直接调用showToast()showToast(content:"添加成功")todos.add(name:newItem)newItem=""}
因为我们是对View进行的扩展,所以,所有的页面和视图都可以调用这些方法
以上,我们实现了一个全局的Toast
踩坑
我曾经思考过,封装一个方法在View上,可以用以下方式调用
self.body.showToast("asdfasdf")
这样我就可以省略入口文件的那个启用方法enableToast()
但是实际上并不会成功,中途倒是没报几个错,但是toast的效果一直都没出来
.popup一定要写在视图定义的后面,而不能在中途的方法调用中动态的执行
也许这就是所谓的强类型+声明式视图???
总结
extension是扩展方法,就说所有的结构都能扩展,包括基础数据类型,用法与js中的prototype比较类似
ViewModifier是对视图的修改,你可以拿到视图本身,添加方法调用,也可以再加一些其他的元素进去,可以理解为拿得到上个页面视图的页面的跳转
全局Loading可以参照上面的实现,无非就是在文字上面加一个Loading的gif动图,本文不再赘述。
包括一些全局的prompt、confirm框等,也可以参照以上实现
貌似popup这个库引入得比较多余,我直接在modifier里面加一个框框在中间,使用ZStack这个框框显示在原始视图的上面不就完事儿了?但是怎么消除Toast是个问题,或许SwiftUI自己处理了这些不显示的视图?这个后续再继续讨论。。。
欢迎