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)
    }
}

调试成果

SwiftUI基础篇ComposingViews

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)
    }
}

调试成果

SwiftUI基础篇ComposingViews

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
            //这不会改动标题的根底设定,只是在根底程度上附加的一种办法。
        }
    }
}

调试成果

SwiftUI基础篇ComposingViews

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())
    }
}

调试成果

SwiftUI基础篇ComposingViews

5、包装自定义UIView

虽然SwiftUI在供给许多UIKit的UIView子类方面做的很好,但目前还没有悉数具有,能够为想要的UIView创立自定义包装器。为UITextView创立SwiftUI包装器作为副文本编辑器的根底,分为四个步骤:

  1. 创立符合UIViewRepresentable的结构体
  2. 定义一个特点来存储正在运用的文本字符串
  3. 给它一个makeUIView()办法,范围TextView
  4. 增加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)
    }
}

调试成果

SwiftUI基础篇ComposingViews

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
            }
        }
    }
}

调试成果

SwiftUI基础篇ComposingViews
SwiftUI基础篇ComposingViews

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)
    }
}

调试成果

SwiftUI基础篇ComposingViews