持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情。
在本章中,你将学会使用Transition
过渡Animation
动画构建一个AppStore
应用市场推荐页面。
项目背景
在AppStore
应用市场中,我们可以看到一个Apple
常用的交互形式,它采用线性动画,当用户点击推荐的卡片视图时,卡片会缓缓弹出,然后进入到对应的详情页中。
这种动画交互很有意思。
那么本章,我们就尝试构建一个AppStore
应用市场推荐页面。
首先,创建一个新项目,命名为SwiftUITransition
。
素材准备
我们先导入一批图片作为卡片视图展示的封面。
Model准备
然后,我们构建下Model
。新建一个swift
类型的文件,命名为Model.swift
。
我们分析下卡片视图所涵盖的内容:封面图片、类目、标题、副标题、内容,我们在Model
中创建对应的参数,并且创建一些示例数据。
import SwiftUI
struct Model: Identifiable {
var id = UUID()
var category: String
var headline: String
var subHeadline: String
var content: String
var image: UIImage
}
#if DEBUG
var sampleModels = [
Model(category: "推荐", headline: "编辑精选", subHeadline: "本周推荐语录", content: "要想在一个生活圈中生活下去,或者融入职场的氛围,首先你要学习这个圈子的文化和发展史,并尝试用这个圈子里面的“话术”和他们交流,这样才能顺利地融入这个圈子。", image: UIImage(named: "image01")!),
Model(category: "热榜", headline: "每日热榜", subHeadline: "今日热门事件推送", content: "对于产品经理来说,用户真正使用产品或产品上线交付后,产品的价值才真正发挥出来。这时候,价值的多少就取决于产品本身所提供的服务,以及产品的设计者后续的运营了。", image: UIImage(named: "image02")!),
Model(category: "头条", headline: "精选头条", subHeadline: "你关注的才是头条", content: "在任何环境中都需要去发现他人身上的优点,但在学习他人优点的同时,也不要忘了自己本身的个人特性,因为这才是你的优点。遇到困难时,我们要迎难而上,而不是畏畏缩缩。找到一个明确的目标,不在乎别人的眼光,努力去做就好了。", image: UIImage(named: "image03")!),
]
#endif
复制代码
我们定义了一个Model
结构体,它遵循Identifiable
协议,这样我们就可以使用id
定位到结构体中的实例。
我们使用var
声明了卡片视图需要用到的变量,并声明了其类型属性:String
、UIImage
等。并创建了一个sampleModels
数组,创建了一个示例数据作为View
视图中展示的内容。
以上就是我们Model
承载的内容,在MVVM
、MVC
开发模式中,基本使用的都是这样的方式。
摘要视图
在AppStore
应用市场推荐页面,我们可以看到可以向下滚动一个个卡片视图。一张张卡片上展示着部分推荐信息,包括文章的图片、类别、标题和副标题。
我们可以创建一个新的结构体用来展示卡片视图。
//摘要视图
struct SummaryView: View {
let category: String
let headline: String
let subHeadline: String
@Binding **var** isShowContent: Bool
var body: some View {
VStack(alignment: .leading) {
Spacer()
Rectangle()
.frame(minHeight: 100, maxHeight: 150)
.overlay(
HStack {
VStack(alignment: .leading) {
Text(self.category.uppercased())
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(.secondary)
Text(self.headline)
.font(.title)
.fontWeight(.bold)
.foregroundColor(.primary)
.minimumScaleFactor(0.1)
.lineLimit(2)
.padding(.bottom, 5)
if !self.isShowContent {
Text(self.subHeadline)
.font(.subheadline)
.foregroundColor(.secondary)
.minimumScaleFactor(0.1)
.lineLimit(3)
}
}
.padding()
Spacer()
}
)
}
.foregroundColor(.white)
}
}
复制代码
上述代码中,我们构建了一个SummaryView
结构体,用来构建卡片视图内容的摘要内容。
我们使用let
声明了类别category
、标题headline
和副标题subHeadline
三个常量及其类型,在结构体主体内容上,我们创建了一个Rectangle
视图,并将和标题和副标题进行overlay
叠加。
叠加部分,我们使用横向视图,包裹了三个Text
文本,Text
文本来源于我们声明的常量,为之后在主视图赋值使用。
这里科普一个知识点。
minimumScaleFactor
修饰符,使用后,Text
文本内容可以根据展示的空间大小自动缩小文本的字体大小。因为考虑到headline
标题和副标题subHeadline
可能会很长的关系,我们这里设定了可以缩小到原始大小的10%
。
完成后,我们在ContentView
视图中展示下内容。
SummaryView(category: sampleModels[0].category, headline: sampleModels[0].headline, subHeadline: sampleModels[0].subHeadline, isShowContent: .constant(false))
复制代码
我们在ContentView
视图实例化了一个SummaryView
视图,数据来源我们使用下标的方式访问sampleModels
数组中的数据,这里取的的是[0]
第一条,对于是否展示内容isShowContent
我们暂时使用false
。
我们预览下效果:
完整视图
完成了摘要视图后,我们来尝试完成完整的视图展示。
struct CardView: View {
let category: String
let headline: String
let subHeadline: String
let image: UIImage
var content: String = ""
@Binding var isShowContent: Bool
var body: some View {
ScrollView {
VStack(alignment: .leading) {
Image(uiImage: self.image)
.resizable()
.scaledToFill()
.frame(height: min(self.image.size.height / 3, 500))
.border(Color(.sRGB, red: 150 / 255, green: 150 / 255, blue: 150 / 255, opacity: 0.1), width: self.isShowContent ? 0 : 1)
.cornerRadius(15)
.overlay(
SummaryView(category: self.category, headline: self.headline, subHeadline: self.subHeadline, isShowContent: self.$isShowContent)
.cornerRadius(self.isShowContent ? 0 : 15)
)
if self.isShowContent {
Text(self.content)
.foregroundColor(Color(.darkGray))
.font(.system(.body, design: .rounded))
.padding(.horizontal)
.padding(.bottom, 50)
.transition(.move(edge: .top))
.animation(.linear, value: 0)
}
}
}
.shadow(color: Color(.sRGB, red: 64 / 255, green: 64 / 255, blue: 64 / 255, opacity: 0.3), radius: self.isShowContent ? 0 : 15)
}
}
复制代码
上述代码中,我们定义了一个CardView
结构体,声明了需要用到的参数:category
类目、headline
主标题、subHeadline
副标题、image
主要展示图片、content
详情内容、以及是否展示内容isShowContent
。
我们在ContentView
视图实例化CardView
视图,和之前摘要视图的方法一致,访问sampleModels
数据数据。
CardView(category: sampleModels[0].category, headline: sampleModels[0].headline, subHeadline: sampleModels[0].subHeadline, image: sampleModels[0].image,content: sampleModels[0].content, isShowContent: .constant(false))
复制代码
我们预览下效果:
我们再把isShowContent
是否展示详情改为true
,再预览下效果。
恭喜你,完成了基础页面的绘制!
由于章节内容过多,我们将分章节进行学习。
快来动手试试吧!
如果本专栏对你有帮助,不妨点赞、评论、关注~