Section 14 : Data and Image Literal

Section 14 : Data and Image Literal - 数据和图像字面量(13’30")

Work with arrays and data models to create a loop of components in SwiftUI.

在 SwiftUI 中使用数组和数据模型创建系列组件。

1. 建立数据模型

上一节的课程卡片只是简单的重复,内容都是一样的。现在如果要展示不一样的内容,可以把他们一致的属性组合成数据模型,其实就是抽象的意思。在SectionView.swift 中的最后声明一个结构体,用来描述抽象出来的数据模型。

struct Section: Identifiable {
    var id = UUID()             // 编号,唯一的
    var title: String           // 标题
    var text: String            // 课时
    var logoName: String        // Logo名
    var image: Image            // 图片
    var color: Color            // 颜色
}

然后再创建一个全局变量用来保存数据并提供给视图使用。为了保存多个课程,将数据类型设为由课程组成的数组。这里暂时先写一个课程。

let sectionData = [
    Section(title: "SwiftUI \n原型设计", text: "共 18 讲", logoName: "Logo1", image: Image("Card1"), color: Color("card1"))
]

2. 在视图用引用数据

(1)修改 SectionView

在视图的 body 前声明一个提供数据的变量 section,声明其类型为 Section。然后将视图中各个组件对应显示的内容改为数据表示。

struct SectionView: View {
    var section: Section        // 声明类型为 Section 的变量用来传递数据
    
    var body: some View {
        VStack {
            HStack(alignment: .top) {
                Text(section.title)         // 使用变量替代原先的静态值
                    .font(.system(size: 24, weight: .bold))
                    .frame(width: 160, alignment: .leading)
                    .foregroundColor(.white)
                
                Spacer()
                
                Image(section.logoName)     // 使用变量替代原先的静态值
            }
            
            Text(section.text)              // 使用变量替代原先的静态值
                .frame(maxWidth: .infinity, alignment: .leading)
            
            section.image                   // 使用变量替代原先的静态值
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 210)
        }
        .padding(.top, 20)
        .padding(.horizontal, 20)
        .frame(width: 275, height: 275)
        .background(section.color)          // 使用变量替代原先的静态值
        .cornerRadius(30)
        .shadow(color: section.color.opacity(0.3), radius: 20, x: 0, y: 20)     // 使用变量替代原先的静态值
    }
}

(2)修改 HomeView

由于 sectionData 是全局的,所以不需要在视图的 body 前再次声明就可以直接在循环中使用。

ForEach(sectionData) { item in                  // 使用变量替代原先的静态值,遍历数组
	SectionView(section: item)                  // 子视图
}

(3)添加几个数据

在 sectionData 中,添加几条数据,数据直接用逗号隔开

let sectionData = [
    Section(title: "SwiftUI \n原型设计", text: "共 18 讲", logoName: "Logo1", image: Image("Card1"), color: Color("card1")),
    Section(title: "SwiftUI \nApp开发", text: "共 20 讲", logoName: "Logo2", image: Image(uiImage:#imageLiteral(resourceName: "wowLM")), color: Color(#colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1))),
    Section(title: "SwiftUI \nMac开发", text: "共 15 讲", logoName: "Logo3", image: Image("Card3"), color: Color("card3"))
]

这样在预览中可以看见有三张卡片了。卡片中的内容就数据提供的。

3. 图像字面量(image literal)

与颜色字面量一样,图像也可以使用字面量。与颜色不同的是,颜色是直接在 Color() 的参数中输入 color literal,图像则需要先输入参数名 uiImage 和冒号:后再输入image literal。然后双击小图标就可以选择 assets 目录下的图像了。

小窍门

在全局变量 sectionData 的声明中,也可以使用字面量。只是没有自动完成的提示。我们可以找个空白行,输入想要的字面量 colorliteral 或者 imageliteral(应该输入到一半多就能有提示出现了),确定后,将色块或者小图标剪切粘贴到变量的声明中,这样下次我们双击色块就可以直接使用字面量了。

本节小结

本节代码请参见 GitHub码云

  • 将具有相同属性的数据抽象成结构体,在视图中声明类型为这个结构体的变量,使用变量的属性将值传递给组件。
  • 数组,方括号括起来的由逗号分隔的一系列同样类型的元素。
  • foreach 用来遍历数组,每次变量会取出当前元素。
  • 图像也可以使用字面量,和颜色字面量不同,需要加上参数名 UIImage:
  • 字面量和预览让原型设计变得非常方便。
接下来

视图滚动时的 3D 动画

return Array.from(sectionMap).map(([name, settings]) => ({ sectionName: name, settings }));这里有报错:Destructuring parameter declarations are not supported (arkts-no-destruct-params) <ArkTSCheck> ; const value = rawItem[key]; 这里 Use explicit types instead of "any", "unknown" (arkts-no-any-unknown) <ArkTSCheck> Indexed access is not supported for fields (arkts-no-props-by-index) <ArkTSCheck> , value: value.map((nestedItem: any) => {:Use explicit types instead of "any", "unknown" (arkts-no-any-unknown) <ArkTSCheck> ; const titles: Partial<Record<SettingKeys, string>> = { :Some of utility types are not supported (arkts-no-utility-types) <ArkTSCheck> ,Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals) <ArkTSCheck>;return titles[key] || key.toString(); :Indexed access is not supported for fields (arkts-no-props-by-index) <ArkTSCheck> ; private getTypeByKey(key: SettingKeys): UISettingItem['type'] { :Indexed access types are not supported (arkts-no-aliases-by-index) <ArkTSCheck> ; const descriptions: Partial<Record<SettingKeys, string>> = { captureLinkage: '抓拍时自动生成一段关联视频', speedOsd: '数据来源于GPS,设备需内置或扩展GPS模块', parkingMonitoringEnable: '停车后自动启动监控功能', parkingSensitivity: '灵敏度设置越高,监测越敏感但电池消耗更快', ADAS: '高级驾驶辅助系统设置', GPS: '全球定位系统配置', cellular: '移动网络配置', parkingMonitoringTime: '设置停车监控的最长持续时间', cloudBox: '云存储服务设置' }; return descriptions[key]; :Some of utility types are not supported (arkts-no-utility-types) <ArkTSCheck> Indexed access is not supported for fields (arkts-no-props-by-index) <ArkTSCheck> ; const newSections = this.sections.map(section => ({ ...section, settings: section.settings.map(item => item.key === key ? { ...item, value } : item :Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals) <ArkTSCheck> ,It is possible to spread only arrays or classes derived from arrays into the rest parameter or array literals (arkts-no-spread) <ArkTSCheck> ; Section({ :Cannot find name 'Section'. Did you mean 'section'? <ArkTSCheck> ; this.SettingGroup({ title: item.title, description: item.description, items: item.value as UISettingItem[] }) Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals) <ArkTSCheck>;:Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals) <ArkTSCheck> ; this.SettingItem({ item: item, onChange: (value) => this.handleSettingChange(item.key, value) }) 'this.SettingItem({ item: item, onChange: (value) => this.handleSettingChange(item.key, value) })' does not comply with the UI component syntax. <ArkTSCheck> Property 'SettingItem' does not exist on type 'Configure'. <ArkTSCheck> ,请帮我修改,并给我完整代码
最新发布
06-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值