首页 > 其他分享 >SwiftUI的认识与使用

SwiftUI的认识与使用

时间:2023-07-31 23:24:10浏览次数:34  
标签:Body struct 认识 视图 SwiftUI 使用 var View

  SwiftUI简介 SwiftUI是苹果推出的一个新的UI框架,它使用了声明的方式,通过视图,基础控件和布局控件来进行页面的开发。 SwiftUI具有跨平台性,一份SwiftUI代码可以同时跑在iOS、macOS、tvOS、watchOS平台上。 SwiftUI编写的页面代码更简洁,广泛使用链式调用。 SwiftUI视图和UIKit视图可以互相转换,对于将旧的项目过度到新布局方式比较友好。 SwiftUI的运行速度优于UIKit,他减少了界面的层次结构,因此可以减少绘制步骤,并且他完全绕过了CoreAnimation,直接进入Metal,可以有优秀的渲染性能。   其实声明式页面布局前端已经出现了很久,像React, Vue都是使用的声明式布局,声明式布局与命令式布局相比有很多优势, 如:单向数据流,双向数据绑定,只要数据状态改变使用了这些数据的视图就会自动更新等。 声明式布局是UI布局方式的未来,这次苹果从命令式编程过度到声明式编程算是一个大的进步。   设计模式 采用Struct组成的树形结构组织页面。叶子节点是基本控件。 这棵Struct树类似于React的抽象语法树,它会在编译阶段将这些描述信息翻译成真实的UIKit中的UI控件。   视图结构 APP根入口 APP的根入口是一个Struct结构体,它遵守APP协议

@main
struct WorldLandMarkApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
App协议
public protocol App {
    associatedtype Body : Scene
 
    @SceneBuilder @MainActor var body: Self.Body { get }
 
    @MainActor init()
}
 

 

页面结构体 some表示返回的是一个遵守了View协议的不透明类型,也就是var body: some View {} 这个计算属性中,只能return一种类型,不能出现if a {Text()} else {List{}} 这样的2种类型。
struct LandmarkList: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
    }
}
View协议 associatedtype Body : View 表示协议中定义了一个新类型Body,这个Body遵守View协议。 Self.Body 表示协议中的Body类型。Self表示类型本身,self表示实例变量本身
public protocol View {
    associatedtype Body : View
    @ViewBuilder @MainActor var body: Self.Body { get }
}
 
每个页面swift文件中都有2个结构体,一个表示要开发的页面,另一个是使用Canvas进行展示出来的视图,其中struct ContentView_Previews: PreviewProvider可以根据Debug需要在外层嵌套导航条,展示Group组。
import SwiftUI
 
struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}
 
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
它们不一定保持一致,如:
struct LandmarkList_Previews: PreviewProvider {
    struct DeviceType: Identifiable {
        var id = UUID()
        var name: String
    }
     
    static var previews: some View {
        //使用ForEach展示多个设备
        ForEach([DeviceType(name: "iPhone 12"),DeviceType(name: "iPhone 13")]){ deviceItem in
            LandmarkList().previewDevice(PreviewDevice(rawValue: deviceItem.name))
                .previewDisplayName(deviceItem.name)
        }
         
    }
}
 

 

状态双向绑定 @State单页面状态绑定 通过@State修饰的变量是做了双向绑定的,如果这个变量数据发生了改变,所有使用这个变量的视图都会自动更新。但是@State的修饰范围是当前的一个视图,如果想一个状态修改,整个APP范围内使用这个变量的视图全部都更新,则需要使用全局环境变量的模式。
@State private var isOpen
struct LandmarkList: View {
     
    @State private var isOpen: Bool = false
    //@ObservedObject: 全局环境变量绑定
    @ObservedObject var userData: UserData = UserData()
}
 
@ObservableObject+@Published全局状态变量 要使用全局状态变量,则需要创建一个class,并遵守ObservableObject协议。 然后在这个类中定义一个@Published修饰的变量 @Published var userLandmarks, 当@Published修饰的变量更新时,那么使用了@Published修饰的变量的视图就会对应更新。 定义一个UserData,遵守ObservableObject协议
import SwiftUI
import Combine
 
class UserData: ObservableObject {
    @Published var userLandmarks:[Landmark] = landmarks
     
}
使用时,也要在对应的视图中加上 @ObservedObject修饰符,然后更新这个变量self.userData.userLandmarks[self.userLandmarkIndex].isFeatured.toggle()
struct LandmarkDetail: View {
    var landmark: Landmark
    @ObservedObject var userData: UserData
     
    var userLandmarkIndex: Int {
        userData.userLandmarks.firstIndex(where: {$0.id == landmark.id})!
    }
 
    var body: some View {
        Button(action: {
            self.userData.userLandmarks[self.userLandmarkIndex]
                .isFeatured.toggle()
        }){
            if landmark.isFeatured {
                Image("icon_rcxinhua_selected")
                    .resizable().frame(width: 20, height: 20, alignment: .center)
            } else {
                Image("icon_rcxinhua_defaultselected")
                    .resizable().frame(width: 20, height: 20, alignment: .center)
            }
        }
    }
}

 

单向数据流 用户操作导致@State变量发生了改变, @State变量改变导致使用了@State变量的UI视图就会自动更新 继续等待用户操作触发@State变量发生变化  

 

UIKit控件与SwiftUI中控件的转换 UIKit转SwiftUI 通过UIViewRepresentable协议将UIView包装成SwifUI的View来使用。
struct MapView: UIViewRepresentable {
    let view: UIView = UIView()
    func makeUIView(context: Context) -> some UIView {
        return view
    }
    func updateUIView(_ uiView: UIViewType, context: Context) {
        view.backgroundColor = .red
    }
}
SwiftUI转UIKit 通过UIHostingController将SwiftUI包装成UIView
UIHostingController(rootView: ContentView())

 

Model模型定义 List,ForEach等要求被循环的每个元素都要有一个唯一的标识 这样数据变更时,可以迅速定位刷新对应的UI,提高性能 所以,元素要遵循Identifiable协议(实现id协议)
struct Landmark: Identifiable {
    var id = UUID()
    let name: String
}

 

Demo地址 https://github.com/zhfei/SwiftBasicKnowledge     参考文章 https://www.jianshu.com/p/0f7215591b08 https://zhuanlan.zhihu.com/p/436779033    

标签:Body,struct,认识,视图,SwiftUI,使用,var,View
From: https://www.cnblogs.com/zhou--fei/p/17595278.html

相关文章

  • Exsi 安装OpenWRT并使用gparted扩容
    Exsi安装OpenWRT并使用gparted扩容所有操作均基于MACOS参考资料下载OpenWRT镜像镜像库地址:https://mirror.sjtu.edu.cn/openwrt/releases/[VERSION_ID]/targets/x86/64/22.03.5下载地址cd~\Downloadswgethttps://mirror.sjtu.edu.cn/openwrt/releases/22.03.5/targ......
  • android中使用startActivityForRes…
    网上找的一个通俗易懂,放在这以后好查阅假设:我这里有两个Activity:A和B,从A中向B中传递数据的时候采用的是Bundle封装数据,然后从A中跳转到B中,当B有需求将数据封装起来回传给A并跳转回A。那么A中接收数据时还要先判断Bundle是否为空,因为第一次访问A的时候(即B还没有回传的时候),Bundle......
  • Android 使用【AIDL】调用外部服务
    在Android中有一种服务说是服务其实倒不如说是一个接口,这个接口名为:AndroidInterfaceDefinitionLanguage,这个接口可提供跨进程访问服务,英文缩写为:AIDL。此种服务的好处在于,多个应用程序之间建立共同的服务机制,通过AIDL在不同应用程序之间达到数据的共享和数据相互操作,下......
  • [Pwn之路]根据所给库,获得远程同环境——使用patchelf的正确姿势
    原文:https://www.freebuf.com/sectool/366854.html存自己这里方便看。0x00前言如何修改本地pwn文件和题目所给环境一致,从而进行调试,这是从学习堆开始就遇到的心头之患。从那以后,直到今天参加完miniLCTF,为了复现一道题目才把这个问题解决掉。网上的博客,参差不齐,由于本人不才,导......
  • 1_认识框架
    1_认识框架框架(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性。是一个基本概念上的结构,用于去解决或者处理复杂的问题。框架这个广泛的定义使用的十分流行,尤其在软件概念。框架(Framework)对于java来说,就是一系列为了解决特定问题而定义的一系列接口和实现......
  • android画图-----shape的使用文档…
    在GradientDrawable1试图中终于把shape学会了,以前总是似懂非懂,现在终于把里面的东西搞清楚了,同时也挺佩服谷歌的用心,故意设置一些陷阱吧,不认真对待还真以为没有啥效果呢。setContentView(R.layout.shape_drawable_1)shape_drawable_1代码如下:<ScrollViewxmlns:android="htt......
  • 使用OpenFeign传递二进制流
    在现代的分布式系统中,服务之间的通信变得越来越普遍。OpenFeign是一个流行的JavaHTTP客户端工具,它简化了在微服务架构中进行服务间通信的过程,本文将简单介绍如何使用OpenFeign传递二进制流。什么是OpenFeign?OpenFeign是一个用于声明式、模板化的HTTP客户端的Java库。它简化了编......
  • C++中不支持strdup(),使用_strdup()
    1.问题C4996 'strdup':ThePOSIXnameforthisitemisdeprecated.Instead,usetheISOCandC++conformantname:_strdup.Seeonlinehelpfordetails. Project1 G:\VS\Project1\Project1\MyString.cpp 802.原因错误C4996是一个编译器警告,它指示在代码中使用了一个......
  • uuid的设计与使用
    UUID全称UniversalUniqueIdentifier是一串128位数字码,用于唯一识别网络对象或者事件。核心思想是结合机器的网卡、当地时间、时间戳,随机数,机器号来生成GUID 项目背景:项目中存在公司基础信息,不同产线的资质信息,合同,银行账号等信息新增场景,需要有一个sid标识公司,使用pid标......
  • Swagger_介绍和使用方式
         然后在浏览器上访问localhost:8080/doc.html就可以测试接口了......