美文网首页
【Swift】100 Days of SwiftUI笔记(23-

【Swift】100 Days of SwiftUI笔记(23-

作者: 酷酷的小虎子 | 来源:发表于2023-08-31 17:12 被阅读0次

笔记

本篇文章记录一下100 Days of SwiftUI第23-25天的笔记内容

为什么 SwiftUI 使用结构体作为视图?

// 性能因素:结构比类更简单、更快
// 迫使我们考虑以一种干净的方式隔离状态,因为类可以自由更改其值,这可能会导致代码更加混乱
// 如果在视图中使用类,可能会发现的代码无法编译或在运行时崩溃,所以使用结构

SwiftUI 主视图背后是什么?

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
            .background(.red)
    }
}
// 这样并不能实现整个屏幕为红色,因为Text背后没有任何东西,想要整个屏幕为红色应该让Text占据整个屏幕的空间
Text("Hello, world!")
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .background(.red)

为什么修饰符顺序很重要?

Button("Hello, world!") {
    // do nothing
}    
.background(.red)
.frame(width: 200, height: 200)
// 以上的代码显示效果并不会看到带有“Hello, world!”的200x200红色按钮,而是看到一个200x200的空方块,上面写着“Hello, world!” 位于中间,并在“Hello, world!”周围有一个红色矩形
// 这是因为:每个修饰符都会应用该修饰符创建一个新结构,而不是仅仅在视图上设置属性
print(type(of: self.body))
// 打印ModifiedContent<ModifiedContent<Button<Text>, _BackgroundStyleModifier<Color>>, _FrameLayout>
// 1.每次我们修改视图时,SwiftUI 都会通过使用泛型来应用该修饰符:ModifiedContent<OurThing, OurModifier>。
// 2.当我们应用多个修饰符时,它们只会叠加:ModifiedContent<ModifiedContent<…
// 3.要读取类型是什么,请从最里面的类型开始并逐步解决,每个类型都需要一个要转换的视图以及要进行的实际更改,而不是直接修改视图,所以首先按钮有一些应用了背景颜色的文本,然后给它一个更大的框架

为什么 SwiftUI 使用“some View”作为其视图类型?

// 1.对性能很重要,SwiftUI 需要能够查看我们显示的视图并了解它们如何变化,以便它可以正确更新用户界面
// 2.因为 SwiftUI 使用ModifiedContent,该View协议有一个关联的类型,所以View它本身没有任何意义,我们需要确切地说出它是什么类型的视图

// VStack是如何工作的?
// 使用VStack时SwiftUI会创建一个TupleView,包含VStack中的视图,TupleView只能处理10个视图,也就是为什么SwiftUI 不允许父级内部有超过 10 个视图的原因

// body中创建视图会做什么处理?
// 与VStack原理相同也是创建一个TupleView包含这些视图,并设置给body的@ViewBuilder这个特殊属性

条件修饰符

// 通常希望修饰符仅在满足特定条件时应用,而在 SwiftUI 中,最简单的方法是使用三元条件运算符
struct ContentView: View {
    @State private var useRedText = false

    var body: some View {
        Button("Hello World") {
            // flip the Boolean between true and false
            useRedText.toggle()            
        }
        .foregroundColor(useRedText ? .red : .blue)
    }
}

环境修饰符

// 许多修饰符可以应用于容器,这允许我们同时将相同的修饰符应用于多个视图
VStack {
    Text("Gryffindor")
        .font(.largeTitle) // 子视图中的修饰符任会替换相同的环境修饰符,Gryffindor会具有大标题
    Text("Hufflepuff")
    Text("Ravenclaw")
    Text("Slytherin")
}
.font(.title)
// 由上述特性可以知道font()是一个环境修饰符

VStack {
    Text("Gryffindor")
        .blur(radius: 0)
    Text("Hufflepuff")
    Text("Ravenclaw")
    Text("Slytherin")
}
.blur(radius: 5)
// 而blur()是一个常规修改器,因此应用于子视图的任何模糊都会添加到VStack模糊中,而不是替换它

视图作为属性

// 有很多方法可以让您更轻松地在 SwiftUI 中使用复杂的视图层次结构,其中一种选择是使用属性 
// 创建一个视图作为您自己视图的属性,然后在布局中使用该属性
struct ContentView: View {
    let motto1 = Text("Draco dormiens")
    let motto2 = Text("nunquam titillandus")

    var body: some View {
        VStack {
            motto1
                .foregroundColor(.red)
            motto2
                .foregroundColor(.blue)
        }
    }
}

// Swift 不允许我们创建一个引用其他存储属性的存储属性,因为这会在创建对象时引起问题
// 这意味着尝试创建TextField与本地属性的绑定将会导致问题
// 但是可以创建计算属性
var motto1: some View {
    Text("Draco dormiens")
}

// 但是与body不用,Swift 不会自动@ViewBuilder在此处应用该属性,因此如果想返回多个视图还需要调整,提供一下3种方式
// 1.将视图放在堆栈中
var spells: some View {
    VStack {
        Text("Lumos")
        Text("Obliviate")
    }
}

// 2.返回一个Group
var spells: some View {
    Group {
        Text("Lumos")
        Text("Obliviate")
    }
}

// 3.自己添加@ViewBuilder属性
@ViewBuilder var spells: some View {
    Text("Lumos")
    Text("Obliviate")
}

视图组成

// SwiftUI 允许我们将复杂的视图分解为更小的视图,而不会产生太大的性能影响
struct ContentView: View {
    var body: some View {
        VStack(spacing: 10) {
            Text("First")
                .font(.largeTitle)
                .padding()
                .foregroundColor(.white)
                .background(.blue)
                .clipShape(Capsule())

            Text("Second")
                .font(.largeTitle)
                .padding()
                .foregroundColor(.white)
                .background(.blue)
                .clipShape(Capsule())
        }
    }
}
// 可以修改为:
struct CapsuleText: View {
    var text: String

    var body: some View {
        Text(text)
            .font(.largeTitle)
            .padding()
            .foregroundColor(.white)
            .background(.blue)
            .clipShape(Capsule())
    }
}

struct ContentView: View {
    var body: some View {
        VStack(spacing: 10) {
            CapsuleText(text: "First")
            CapsuleText(text: "Second")
        }
    }
}

自定义修饰符

// SwiftUI允许创建执行特定操作的自定义修饰符
// 创建一个符合ViewModifier协议的新结构,且必须调用body方法接受要使用的内容,并且必须返回some View
struct Title: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.largeTitle)
            .foregroundColor(.white)
            .padding()
            .background(.blue)
            .clipShape(RoundedRectangle(cornerRadius: 10))
    }
}

Text("Hello World")
    .modifier(Title())

// 使用自定义修饰符时,j建议创建View扩展使用
extension View {
    func titleStyle() -> some View {
        modifier(Title())
    }
}

Text("Hello World")
    .titleStyle()

// 自定义修饰符还可以根据需要创建新的视图结构
struct Watermark: ViewModifier {
    var text: String

    func body(content: Content) -> some View {
        ZStack(alignment: .bottomTrailing) {
            content
            Text(text)
                .font(.caption)
                .foregroundColor(.white)
                .padding(5)
                .background(.black)
        }
    }
}

extension View {
    func watermarked(with text: String) -> some View {
        modifier(Watermark(text: text))
    }
}

Color.blue
    .frame(width: 300, height: 200)
    .watermarked(with: "Hacking with Swift")

相关文章

网友评论

      本文标题:【Swift】100 Days of SwiftUI笔记(23-

      本文链接:https://www.haomeiwen.com/subject/uxxmmdtx.html