ComposingView
- 创立和组合自定义视图
- 将文本视图组合在一起
- 将视图存储为特点
- 创立自定义润饰符
- 包装自定义UIView
- 如何为UIViewRepresentable结构创立润饰符
- 如安在文本中刺进图画
概述
文章首要分享SwiftUI Modifier的学习进程,将运用事例的办法进行说明。内容深入浅出,ComposingView部分调试,不过测验代码是齐全的。假如想要运转成果,能够移步Github下载code -> github事例链接
1、创立和组合自定义视图
SwiftUI的核心之一就是组合
,这意味着能够创立许多小视图,然后将他们组合以创立更大、更复杂的视图。这能够大规模的重用视图,这意味着工作量减少了。更好的情况下,组合视图运转时简直不会造成额定的开支,因此能够随意运用而不用介意功能。这儿我复刻一个完好的个人信息的比方。
Employee结构体
人物信息结构体
struct Employee {
var name: String
var jobTitle: String
var emailAddress: String
var profilePicture: String
}
ProfilePicture头像视图
App中的职工个人资料有头像图片,能够创立一个圆形的视图
struct ProfilePicture: View {
var imageName: String
var body: some View {
Image(imageName)
.resizable()
.frame(width: 100, height: 100)
.clipShape(Circle())
}
}
EmailAddresss视图
struct EmailAddress: View {
var address: String
var body: some View {
HStack {
Image(systemName: "envelope")
Text(address)
}
}
}
EmployeeDetail详细信息视图
struct EmployeeDetail: View {
var employee: Employee
var body: some View {
VStack(alignment: .leading) {
Text(employee.name)
.font(.largeTitle)
.foregroundStyle(.primary)
Text(employee.jobTitle)
.foregroundStyle(.secondary)
EmailAddress(address: employee.emailAddress)
}
}
}
EmployeeView整合视图
创立一个更大的视图,将ProfilePicture与Employee组合,供给整体的职工信息
struct EmployeeView: View {
var employee: Employee
var body: some View {
HStack {
ProfilePicture(imageName: employee.profilePicture)
EmployeeDetail(employee: employee)
}
}
}
经过别离的结构,能够用很多种办法来展现职工的信息:
- 只显示头像
- 只显示电子邮件
- 只显示职工具体信息
- 显示一切信息
更重要的是,这意味着当涉及到运用这些struct时,首要的内容视图不必忧虑如何构建这些内容的布局,由于它只包括一个大的视图,一切的这些布局都被融入到较小的视图中。这就意味着我只要在body中创立一个EmployeeView就能够了。
自定义视图的运用
struct FFCustomView: View {
//构建数据
let employee = Employee(name: "Meta BBLv", jobTitle: "Keep Loving, Keep Living", emailAddress: "metabblv@163.com", profilePicture: "chrysanthemum-tea-thumb")
var body: some View {
EmployeeView(employee: employee)
}
}
调试成果
2、将文本视图组合在一起
SwiftUI文本视图重载了“+”
运算符,能够将文本视图组合创立新的文本视图。当需要在视图中运用不同的格式时,能够使每个文本视图都不一样,然后将它们衔接在一起构成单个组合文本视图。最便利的是,当运用朗诵功能时,VoiceOver会主动将它们识别为一段文本。
struct FFCustomText: View {
var body: some View {
Text("SwiftUI")
.font(.largeTitle)
+ Text("is")
.font(.headline)
+ Text("awesome")
.font(.footnote)
//创立不同色彩或字体的文本
Text("SwiftUI")
.foregroundStyle(.red)
+ Text("is")
.foregroundStyle(.orange)
.fontWeight(.black)
+ Text("awesome")
.foregroundStyle(.blue)
}
}
调试成果
3、将视图存储为特点
假如有多个视图嵌套在另一个视图中,你可能会发现为其间一些或悉数视图创立特点很重要,能够使布局代码更容易,然后,能够在视图代码中內联引证这些特点,能够保证视图结构更清晰。
struct FFViewStoreProperties: View {
let title = Text("metaBBLv").bold()
let subtitle = Text("Author").foregroundStyle(.secondary)
var body: some View {
VStack {
title
subtitle
//像这样,只需要在stack中写入特点名就能够运用了。
//但是更便利的是能够将润饰符附加到这些特点上进行自定义操作。
Divider()
title
.foregroundStyle(.red)
subtitle
//这不会改动标题的根底设定,只是在根底程度上附加的一种办法。
}
}
}
调试成果
4、创立自定义润饰符
假如发现重复的将同一组润饰符附加到视图(比方,背景色、padding、字体等等),那么能够经过创立一个润饰符来封装这些重复的润饰符。假如你想创立自己的结构,那么要恪守ViewModifier
协议。并且要实现一个body(content:)函数。
//创立一个新的PrimaryLabel润饰符,增加padding、background、foregroundcolor和font等
struct PrimaryLabel: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(.red)
.foregroundStyle(.white)
.font(.largeTitle)
}
}
struct FFCustomModifiers: View {
var body: some View {
Text("Hello, SwiftUI")
.modifier(PrimaryLabel())
}
}
调试成果
5、包装自定义UIView
虽然SwiftUI在供给许多UIKit的UIView子类方面做的很好,但目前还没有悉数具有,能够为想要的UIView创立自定义包装器。为UITextView创立SwiftUI包装器作为副文本编辑器的根底,分为四个步骤:
- 创立符合UIViewRepresentable的结构体
- 定义一个特点来存储正在运用的文本字符串
- 给它一个makeUIView()办法,范围TextView
- 增加updateUIView()办法,每逢TextView的数据发生更改时都会调用该办法。
struct TextView: UIViewRepresentable {
@Binding var text: NSMutableAttributedString
func makeUIView(context: Context) -> some UIView {
UITextView()
}
func updateUIView(_ uiView: UIViewType, context: Context) {
uiView.accessibilityAttributedLabel = text
}
}
struct FFCustomViewWrap: View {
@State private var text = NSMutableAttributedString(string: "")
var body: some View {
//在SwiftUI视图中运用TextView组件
TextView(text: $text)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
调试成果
6、如何为UIViewRepresentable结构创立润饰符
将UIView包装在UIViewRepresentable
结构中是将现有UIKit引进SwiftUI工程的办法,甚至能够增加自定义润饰符来调整视图在运转时的状况。
要实现这个需求,应该要在底层UIView上调整的一切值创立私有特点,然后创立办法来调整它们,这些办法中的每一个都能够获取SwiftUI可表示副本(而不是底层UIView),然后调整自己创立的私有特点来更新状况。
完成后,SwiftUI将保证触发updateUIView()函数,此时你将私有特点复制到UIView中以保证更新。
SearchField
创立一个UIViewRepresentable将UISearchBar桥接到SwiftUI,但你可能希望它的某些方面是可定制的,例如她的占位符文本。首要,创立可表示目标,并为其占位符增加一个额定的私有特点。
struct SearchField: UIViewRepresentable {
@Binding var text: String
private var placeholder = ""
init(text: Binding<String>) {
_text = text
}
func makeUIView(context: Context) -> some UIView {
let searchBar = UISearchBar()
searchBar.placeholder = placeholder
return searchBar
}
func updateUIView(_ uiView: UIViewType, context: Context) {
let view: UISearchBar = uiView as! UISearchBar
view.text = text
view.placeholder = placeholder
}
}
创立润饰符调整私有特点
extension SearchField {
func placeholder(_ string: String) -> SearchField {
var view = self
view.placeholder = string
return view
}
}
运用自定义的润饰符
运用placeholder()润饰符创立了一个SearchField视图,但每次单击按钮时,会随机化占位符
struct FFCreateModifiers: View {
@State private var text = ""
@State private var placeHolder = "Hello, wrold"
var body: some View {
VStack {
SearchField(text: $text)
.placeholder(placeHolder)
//每次按下时随机更换占位符
Button("Tap me") {
placeHolder = UUID().uuidString
}
}
}
}
调试成果
7、如安在文本中刺进图画
SwiftUI能够运用“+”来组合文本视图,也能够运用简略的文本初始值设定项将图画直接放到文本中。
struct FFTextInsertImage: View {
var body: some View {
//在Helloworld中增加一个星星icon
Text("Hello ") + Text(Image(systemName: "star")) + Text(" World!")
//文本中的图画将主动调整以匹配增加的润饰符(字体、色彩等),要用括号将链接的内容扩起来,以保证将润饰符应用于整个链接的文本。要不只能润饰最后一个Text
(Text("Hello ") + Text(Image(systemName: "star")) + Text(" World!"))
.font(.largeTitle)
.foregroundStyle(.blue)
//假如没有增加额定的括号,则只会润饰最后一个Text("World")
Text("Hello ") + Text(Image(systemName: "star")) + Text(" World!")
.font(.largeTitle)
.foregroundStyle(.blue)
}
}
调试成果