将用户添加到sudoers_SwiftUI入门三:处理用户输入

02179c0f72e0e87e08dcfbb677af65e4.png

在Landmark App中,用户应该要能收藏他们喜欢的地方,并过滤列表只显示他们收藏的。要创建这些特性,我们通过在列表中添加一个切换控件让用户只看到他们收藏的那些地标,然后添加一个星形按钮,用户点击之后会将这个地标标记为收藏的。

<下载>启动项目并跟随本教程,或打开完成的项目自己研究代码。

01 标记用户喜欢的地标

通过加强列表为用户显示他们收藏的地标开始。在每个LandmarkRow中添加一个星标显示收藏的地标。

2fcf3dd00985ff11c9b5257f59181e8d.png

第一步
打开初始的Xcode项目,然后在项目导航器中选中LandmarkRow.swift文件。

36819f1c360333ed3ef431440deddbcb.png

第二步
Spacer控件后,添加一个if语句判断当前地标是否是收藏的,并在语句中添加星形图片。

在SwiftUI代码块中,我们使用if语句来根据条件包含视图。

            Text(landmark.name)
            Spacer()

            if landmark.isFavorite {
                Image(systemName: "star.fill")
                    .imageScale(.medium)
            }
        }
    }

第三步
由于系统图片是矢量的,我们可以使用foregroundColor(_:)修饰器改变它们的颜色。

星形控件会在地标的isFavorite属性为true时显示。我们之后会学习如何修改这个属性。

                Image(systemName: "star.fill")
                    .imageScale(.medium)
                    .foregroundColor(.yellow)
            }
        }

02 过滤列表视图

我们可以定制列表视图,让它显示所有的地标,或是只显示用户收藏的。要实现这个功能,我们需要在LandmarkList类中添加一些状态。

状态是指一个值,或是一组值,它们可能会随时变化,并相应地影响视图的表现,内容或布局。我们使用带有@State标的属性将状态添加到视图中。

33ffdf8dab0ec8e841e20d86540fa1d7.png

第一步
在项目导航器中选中LandmarkList.swift文件,在LandmarkList类中添加一个带有@State标注的变量showFavoritesOnly,并将其初始值设置为false

struct LandmarkList: View {
    @State var showFavoritesOnly = false

    var body: some View {
        NavigationView {

第二步
点击Resume按钮刷新画布。

当我们对视图的结构做了变更,比如添加或修改了属性时,我们需要手动刷新画布。

468755eeccf0b2a96f1dc6dea59e979f.png

第三步
通过检测showFavoritesOnly属性和每个地标的landmark.isFavorite值过滤地标列表。

        NavigationView {
            List(landmarkData) { landmark in
                if !self.showFavoritesOnly || landmark.isFavorite {
                    NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                    }
                }
            }

03 添加控件触发状态切换

要让用户可以控制列表过滤与否,我们需要添加一个控件来修改showFavoritesOnly的值。这里通过绑定一个开关控件来实现。

绑定是与可变状态建立联系。当用户点击开关控件从关闭到打开,再到关闭的时候,控件使用绑定相应的更新视图的状态。

bde7d725487945e21b7f7e6ffef94b44.png

第一步
创建一个嵌套的ForEach组,将地标转换为行视图。

要组合静态和动态视图到一个列表中,可组合两个或更多不同组的动态视图,使用ForEach类型而不是将集合数据传入列表。

struct LandmarkList: View {
    @State var showFavoritesOnly = true
    
    var body: some View {
        NavigationView {
            List {
                ForEach(landmarkData) { landmark in
                if(!self.showFavoritesOnly || landmark.isFavorite) {
                    NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                        LandmarkRow(landmark: landmark)
                        }
                    }
                }
            }

第二步
添加一个Toggle视图作为列表的第一个子视图,传入一个showFavoritesOnly绑定。

使用$前缀来访问状态变量的绑定,或它的一个属性。

        NavigationView {
            List {
                Toggle(isOn: $showFavoritesOnly) {
                    Text("Favorites only")
                }

                ForEach(landmarkData) { landmark in
                    if !self.showFavoritesOnly || landmark.isFavorite {

第三步
使用实时预览并尝试点击新添加的开关控件的功能。

cb0eb9f851d4eb45d431b9d00eeaf0be.gif

04 为存储使用可观察对象

为了准备让用户控制哪个地标是收藏了的,我们首先需要将地标数据存储在可观察对象中。

可观察对象是一个为数据自定义的对象,在SwiftUI环境中可以将存储与视图绑定。SwiftUI会监视可观察对象可能会导致UI变化的数据改变,并在数据改变后显示正确的视图版本。

d079edbe36ed0798a97016348bbc5790.png

第一步
创建一个Swift文件命名为UserData.swift

import SwiftUI

第二步
声明一个新的model遵从Combine框架中的ObservableObject协议。

SwiftUI可以订阅可观察对象,并在数据改变的时候更新需要刷新的视图。

import SwiftUI
import Combine

final class UserData: ObservableObject  {

}

第三步
showFavoritesOnly和地标数组添加存储属性,并初始化。

final class UserData: ObservableObject  {
    var showFavoritesOnly = false
    var landmarks = landmarkData
}

一个可观察对象需要公布任何对数据的变更,这样订阅者才能知道数据变更了。

第四步
为model中每个数据添加@Published标注。

final class UserData: ObservableObject  {
    @Published var showFavoritesOnly = false
    @Published var landmarks = landmarkData
}

05 在视图中使用model对象

现在我们已经创建了UserData对象,需要更新视图将其作为数据存储。

9c4235cec3ebaa14dacbe1e0e0fd885f.png

第一步
LandmarkList.swift文件中,用@EnvironmentObject属性替换showFavoritesOnly的声明,并在预览中添加environmentObject(_:)修饰器。

这个userData属性会在environmentObject(_:)修饰器应用到父视图中后自动获取它的值。

struct LandmarkList: View {
    @EnvironmentObject var userData: UserData

    var body: some View {

第二步
使用userData访问相同的属性替换showFavoritesOnly的使用。

@State标注的属性一样,在userData对象前添加$前缀绑定并访问它的成员属性。

        NavigationView {
            List {
                Toggle(isOn: $userData.showFavoritesOnly) {
                    Text("Favorites only")
                }

第三步
使用userData.landmarks作为数据源创建ForEach实例。

                }

                ForEach(userData.landmarks) { landmark in
                    if !self.userData.showFavoritesOnly || landmark.isFavorite {
                        NavigationLink(destination: LandmarkDetail(landmark: landmark)) {

第四步
SceneDelegate.swift文件中,为LandmarkList添加environmentObject(_:)修饰器。

如果在模拟器或设备中构建并运行Landmarks App,相比在预览中使用,这个更新确保了LandmarkList在环境中会拥有UserData对象。

第五步
更新LandmarkDetail视图使用环境中的UserData对象。

在访问或更新地标的收藏状态时,我们会使用landmarkIndex,这样我们就可以访问正确版本的数据。

struct LandmarkDetail: View {
    @EnvironmentObject var userData: UserData
    var landmark: Landmark
        
    var landmarkIndex: Int {
        userData.landmarks.firstIndex(where: { $0.id == landmark.id })!
    }
struct LandmarkDetail_Previews: PreviewProvider {
    static var previews: some View {
        let userData = UserData()
        return LandmarkDetail(landmark: userData.landmarks[0])
            .environmentObject(userData)
    }
}

第六步
切换回LandmarkList.swift文件并打开实时预览来验证所有功能按预期运行。

45d9801174c9ffe332149441944bf07b.png

06 为每个地标创建收藏按钮

现在Landmarks App可以在过滤和未过滤地标视图中切换了,但是列表的收藏状态还是硬编码的。为了让用户可以添加或移除收藏,我们需要在地标详情页添加收藏按钮。

4fe3c284be966fe4bf2bcce314ad24db.png

第一步
LandmarkDetail.swift文件中,将地标的名字嵌套进HStack。

            VStack(alignment: .leading) {
                HStack {
                    Text(landmark.name)
                        .font(.title)
                }

                HStack(alignment: .top) {
                    Text(landmark.park)

第二步
在地标名字旁边创建一个按钮,使用if-else条件语句根据地标是否已经收藏显示不同的图片。

在按钮的action闭包中,我们使用userData配合landmarkIndex更新当前的地标数据。

                    Text(landmark.name)
                        .font(.title)

                    Button(action: {
                        self.userData.landmarks[self.landmarkIndex].isFavorite.toggle()
                    }) {
                        if self.userData.landmarks[self.landmarkIndex].isFavorite {
                            Image(systemName: "star.fill")
                                .foregroundColor(Color.yellow)
                        } else {
                            Image(systemName: "star")
                                .foregroundColor(Color.gray)
                        }
                    }
                }

第三步
切换回LandmarkList.swift文件,并打开实时预览。

当我们从列表导航到详情页并点击了收藏按钮,在返回列表页时这些变更会存储下来。由于这两个视图都会访问环境中的同一个model,它们的状态会保持一致。

b78896518a78eed480136a746470abc0.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值