文章目录
1. 使用 GeometryReader 调整尺寸
.resizable() 设置图片尺寸是可以被调整的
.frame(width:300, height: 300) 调整图片尺寸
.aspectRatio(contentMode: .fit) 保持长宽比例
GeometryReader 可以使图片更好的显示
GeometryReader{ geo in
Image("road")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geo.size.width, height: 300)
}
2. 滚动视图 ScrollView
import SwiftUI
struct CustomText: View{
var number: Int
var body: some View{
Text("CustomText \(number)")
}
init(_ number: Int){
self.number = number
print("CustomText \(number)")
}
}
struct ContentView: View {
var body: some View {
ScrollView(.vertical){
VStack{
ForEach(0...100, id:\.self){
CustomText($0)
.font(.title)
}
}
}
}
}
3. NavigationLink
SwiftUI中的NavigationView采用的是“视图堆栈”的操作机制。它会在APP界面的顶部显示一个导航栏,用来指示我们当前是哪一个视图。
所谓的“视图堆栈”机制就是当前显示的视图是在“栈顶”的,当需要打开新的视图时,就把新的视图‘‘入栈”,让这个新的视图称为新的栈顶。当我们在导航栏中点击“back”时,相当于让当前的视图“出栈”,而之前在栈中“原来栈顶”下面的那个视图就成了“新的栈顶
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
NavigationLink(destination: Text("world")){
Text("Hello")
}
.navigationBarTitle("SwiftUI")
}
}
}
上述代码中的第6行使用了NavigationLink来创建导航,它的参数destination可以是任何view类成员,一个Text,一个button,-个view均可。
这种机制跟之前学过的“sheet”的方式显示新的视图是不一样的。
-
NavigationLink 有些类似于剥洋葱,-层一层的剥开,一层一层的深入去展示。
-
sheet有些类似于它就是这个视图的一个组成部分,只不过不需要显示它的时候就把它隐藏起来,需要的时候再让它显示出来。
如果在NavigationLink中使用了List, 那么会在每- -行的后面都出现一一个“>”,用于指示用户点击可进入下一层。
4. 使用 Codable 对多层级的 JSON 进行压缩
// ****** ?? 3?******
Button("解析圆形"){
let myCircle = """
{
"radius": 10.4,
"point": {
"x": 12.0,
"y": -15.3
}
"""
}
struct Circle: Codable{
var radius: Double
var point: PointXY
}
struct PointXY: Codable{
var x: Double
var y: Double
}
//解析上面数据的代码
let data = Data(myCircle.utf8)
let decoder = JSONDecoder()
if let circle = try? decoder.decode(Circle.self, from: data) {
print(circle.point.x)
}
}
5. 扩展Bundle
// ****** Astronaut.swift ******
import Foundation
struct Astronaut: Codable, Identifiable{
var id: Int
var name: String
var description: String
}
// ****** Bundle-Decodable.swift ******
import Foundation
extension Bundle {
func decode<T: Codable>(_ file: String) -> T {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
guard let loaded = try? decoder.decode(T.self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}
return loaded
}
}
在ContentView中编写代码
let astronauts = Bundle.main.decode("astronaut.json")
6.案例
6.1 json数据
novels.json
[
{
"id": 1,
"list": [
{
"name": "两钱铜币",
"author": "(日)江户川乱步"
},
{
"name": "人生",
"author": "路遥"
},
{
"name": "鬼谷子的局",
"author": "寒川子"
}
],
"description": "电子书畅销小说"
},
{
"id": 2,
"sort": "社会生活小说",
"list": [
{
"name": "人生",
"author": "路遥"
},
{
"name": "边城",
"author": "沈从文"
},
{
"name": "海边的卡夫卡",
"author": "(日)村上春树"
}
],
"description": "《人生》是获得茅盾文学奖的作品,《边城》是我国文学大师沈从文久负盛名的作品,《海边的卡夫卡》是村上春树仅次于《挪威的森林》的重要长篇小说。"
},
{
"id": 3,
"sort": "历史小说",
"list": [
{
"name": "鬼谷子的局",
"author": "寒川子"
},
{
"name": "巨人的陨落",
"author": "(英)肯·福莱特"
}
],
"description": "《鬼谷子的局》是一部巨著,全书共十卷,讲述谋略家、兵法家、纵横家、阴阳家、道家共同的祖师爷——鬼谷子布局天下的辉煌传奇。《巨人的陨落》是全球读者平均3个通宵读完的超级巨著。碾压全球畅销榜的伟大故事,全球每三秒卖出一本!"
},
{
"id": 4,
"sort": "侦探悬疑小说",
"list": [
{
"name": "两钱铜币",
"author": "(日)江户川乱步"
},
{
"name": "梦幻花",
"author": "(日)东野圭吾"
},
{
"name": "无人生还",
"author": "(英)阿加莎·克里斯蒂"
}
],
"description": "当当网侦探悬疑推理类的热销小说"
}
]
books.json
[
{
"id": "两钱铜币",
"author": "(日)江户川乱步 著 王志芳 译",
"price": "6.99",
"description": "江户川乱步(1894—1965)是日本久富盛名的推理作家、评论家,被誉为日本“侦探推理小说之父”,其笔下的侦探明智小五郎(《名侦探柯南》中毛利小五郎姓名由来,其本人为《名侦探柯南》中江户川柯南姓由来)更是日本家喻户晓的人物。 江户川乱步的中短篇代表作,小说内容取材广泛,构思拍案叫绝、气氛妖异诡谲、情节跌宕起伏,不读到最后一刻,永远不会知道真相是什么!本套书共分两册,将收录江户川乱步最为经典的侦探小说,例如《两钱铜币》《湖畔亭离奇命案》《月亮与手套》《心理测试》《地狱的面具》《出没于顶棚里的人》《D坂街杀人事件》等。"
},
{
"id": "梦幻花",
"author": "(日)东野圭吾",
"price": "9.90",
"description": "错综交织的悬案,揭百年的谜团 年轻夫妇的身体被武士刀贯穿,仅有年幼的女儿生还; 一见钟情的初恋女孩,却在几天后人间蒸发; 大学生跳楼身亡,桌上摆着半杯可乐; 独居老人疑被室强盗杀害,丢失的财物却是一盆鲜花…… “梦幻花”究竟是什么?为什么一旦追寻就会自取灭亡? 源自真实故事的创作灵感 日本的江户时代出现过黄色的牵牛花。为什么到现在反而没有了呢? 想到这里,一股悬疑的气息袅袅升起。"
},
{
"id": "无人生还",
"author": "(英)阿加莎·克里斯蒂",
"price": "6.99",
"description": "十个相互陌生、身份各异的人受邀前往德文郡海岸边一座孤岛上的豪宅。客人到齐后,主人却没有出现。当晚,一个神秘的声音发出指控,分别说出每个人心中罪恶的秘密。接着,一位客人离奇死亡。暴风雨让小岛与世隔绝,《十个小士兵》——这首古老的童谣成了死亡咒语。如同歌谣中所预言的,客人一个接一个死去……杀人游戏结束后,竟无一人生还!"
},
{
"id": "人生",
"author": "路遥",
"price": "18.99",
"description": "《人生》是茅盾文学奖得主路遥的代表作,激励万千读者的文学经典。《人生》改变了马云的一生,也深刻影响了陈忠实、贾樟柯等人的创作。 《人生》以陕北高原的城乡生活为背景,叙述了知识青年高加林回到家乡又离家乡,再回归家乡的人生变化过程。《人生》讲述了一个年轻人面临的爱情与事业、理想与现实间的艰难选择,具有巨大的共情力量,说出了每个人,尤其是年轻人的困境、期待与追求。《人生》在有限生命中不懈追寻的激情,在每个人的心底激起回响;《人生》大地般宽广的气质,给予对生活失望的人莫大的安慰与力量。这是路遥的《人生》,也是我们每个人的人生。"
},
{
"id": "边城",
"author": "沈从文",
"price": "5.99",
"description": "《边城》是沈从文久负盛名的作品,由此奠定了他在中国现代文学史上的地位。它入选“20世纪中文小说百强”第二名,并被翻译成40多个国家的文字出版,亦被编入美国、日本等十多个国家和地区的大学课本。 这是一部田园牧歌式的杰作。在这部小说中,沈从文描绘了一个如同世外桃源般的边城小镇,以及一个纯粹、美丽而淡淡忧伤的爱情故事。在他的笔下,湘西淳朴天然的人情世道,野性自由的生命形态,以及澄澈纯净的人性,均一一铺呈开来,婉约而惆怅。沈从文关于“爱”与“美”的美学理想,在这部小说中得到了完整的体现。 本书另外还收录了《三三》《萧萧》等沈从文具有代表性的小说作品,基本囊括了沈从文文字精髓,全面展示了大师的文风神采。"
},
{
"id": "海边的卡夫卡",
"author": "(日)村上春树",
"price": "12.99",
"description": "本书是村上春树仅次于《挪威的森林》的重要长篇小说,以其独特风格的两条平行线展。一条平行线是少年“田村卡夫卡”,为了挣脱“你要亲手杀死父亲,与母亲乱伦”的诅咒,离家乡投成人世界。此后父亲在家被杀,他却疑心自己是在睡梦中杀父。他在一座旧图书馆遇到一位50岁的优雅女性,梦中却与这位女性的少女形象交合,而这位女性又可能是他的生母。一条平行线是一名失忆老人中田,因为一桩离奇的杀人事件走上逃亡之路,在汽车司机星野的帮助下恢复了遥远的战争记忆。书中对日本军国主义的复活表达了忧虑,对日本的文化传统作出了反思。本书平装本2003年由我社初版,此后于2007年更换了封面,并作了修订。2014年,我社又出版了本书的精装本,再次作了修订。因上一个平装本封面已经10年未变,故第三次更换本书封面设计,使这部名作焕发新的活力。"
},
{
"id": "鬼谷子的局",
"author": "寒川子",
"price": "19.99",
"description": " 本书为《鬼谷子的局》第五卷。在本卷中天下大势瞬息万变,转眼间,四子山已过三年。庞涓习得《吴起兵法》,自觉技艺已成,告别鬼谷子和其余三人下山。他先齐,再魏,助魏惠王与七万齐军决战黄池,退秦、赵、韩联军,尽解魏围。 由此,庞涓封侯拜将,名扬天下。他的杀父仇人陈轸深惧报复,仓皇投秦。 另一方面,魏惠王急使太子申重金礼聘孙宾下山。下山前,鬼谷子为孙宾更名为“孙膑”。 之后孙膑辅佐庞涓献屯田之谋,使魏国军力财力迅速复苏,隐隐有称霸七国之相。这让苏秦、张仪也禁不住跃跃欲试,但鬼谷子却以学艺未成为由,刻意挽留二人,授予其纵横捭阖之术。"
},
{
"id": "巨人的陨落",
"author": "(英)肯·福莱特(KenFollett)(著),于大卫(译)",
"price": "19.99",
"description": " 在第一次世界大战的硝烟中,每一个迈向死亡的生命都在热烈地生长――威尔士的矿工少年、刚失恋的美国法律系大学生、穷困潦倒的俄国兄弟、富有英俊的英格兰伯爵,以及痴情的德国特工……从充满灰尘和危险的煤矿到闪闪发光的皇室宫殿,从代表着权力的走廊到爱恨纠缠的卧室,五个家族迥然不同又纠葛不断的命运逐渐揭晓,波澜壮阔地展现了一个我们自认为了解,但从未如此真切感受过的20世纪。"
}
]
6.2 结构体定义
Book
// ****** Book.swift ******
import Foundation
struct Book: Codable, Identifiable {
let id: String
let author: String
let price: String
let description: String
}
Novel
// ****** Novel.swift *******
import Foundation
struct Novel: Codable, Identifiable{
struct CrewList: Codable{
let name: String
let author: String
}
let id: Int
var sortVar: String?
let crew: [CrewList]
let description: String
var displayName: String{
"Novel \(id)"
}
var image: String{
"novel \(id)"
}
//软解包
if let sort = sortVar{
}else{
print("nil")
}
}
6.3 BookView
BookView
import SwiftUI
struct BookView: View {
let book: Book
var body: some View {
GeometryReader{ geometry in
ScrollView(.vertical){
VStack{
Image(self.book.id)
.resizable()
.scaledToFit()
.frame(width: geometry.size.width)
Text(self.book.author)
Text(self.book.price)
Text(self.book.description)
.padding()
.layoutPriority(1)
}
}
}
.navigationBarTitle(Text(book.id),displayMode: .inline)
}
}
struct BookView_Previews: PreviewProvider {
static let books: [Astronaut] = Bundle.main.decode("books.json")
static var previews: some View {
BookView(book: books[0])
}
}
6.4 NovelView
import SwiftUI
struct NovelView: View {
struct CrewMember{
let name: String
let author: String
let book: Book
}
let novel: Novel
let books: [CrewMember]
init(novel: Novel, books: [Book]){
self.novel= novel
//定义一个空的数组存放 books
var matches = [CrewMember]()
for member in novel.crew{
if let match = books.first(where: {
$0.id == member.name
}){
matches.append(CrewMember(name: member.name,author: member.author, book: match))
}else{
fatalError("Missing \(member)")
}
}//for
self.books= matches
}
var body: some View {
GeometryReader{ geometry in
ScrollView(.vertical){
VStack{
Image(self.novel.image)
.resizable()
.scaledToFit()
.frame(maxWidth:geometry.size.width * 0.7)
.padding(.top)
Text(self.novel.sort)
Text(self.novel.description)
.padding()
ForEach(self.books, id:\.id){ crewMember in
NavigationLink(destination: BookView(book: crewMember.book)){
HStack{
Image(crewMember.book.id)
.resizable()
.frame(width: 83, height: 60)
.clipShape(Capsule())
VStack(alignment:.leading){
Text(crewMember.book.id)
.font(.headline)
Text(crewMember.book.author)
.foregroundColor(.secondary)
}
Spacer()
}
.padding()
}
.buttonStyle(PlainButtonStyle())
}
Spacer(minLength: 25)
}
}
}//GeometryReader
.navigationBarTitle(Text(novel.displayName),displayMode: .inline)
}//View
}//NovelView
struct NovelView_Previews: PreviewProvider {
static let novels: [Novel] = Bundle.main.decode("novels.json")
static let books: [Book] = Bundle.main.decode("books.json")
static var previews: some View {
NovelView(novel: novels[0], books: books)
}
}
ContentView