这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战
一、引言
本期实战,仿写iPhone
自带的天气APP
。
左边是真正的天气App
,右边是仿写的。
二、首要任务-布局
写这个APP
首先要考虑的,是整体的布局,比如这个APP
,是可以滑动到底的,也就是说内容无法一个页面内全部展开显示,需要通过滑动展示其余的内容。基于此,使用ScrollView
和LazyVStack
的二人组是必须的。ScrollView
可以使页面内容无限制高度;LazyVStack
可以优化大量内容的渲染延迟加载,提高性能。
ScrollView{
LazyVStack{
//内容如下
}
}
其次,背景图片要伴随这个滚动视图,先通过ZStack
叠加ScrollView
和Image
,然后调整Image
伸展到全部。
ZStack{
Image("weather").resizable() //重置视图尺寸,默认伸展全部。
ScrollView{
LazyVStack{
}
}
}
三、主题区域
这部分也很简单,4个Text
组件,赋上内容、再调整下字体大小和颜色即可。
VStack{
Text("昌平区").font(.title)
Text("局部多云")
Text("26").font(.system(size: 75))
Text("最高29 最低22").bold()
}.padding(.top, 50)
四、AQI
这部分可以拆分成4部分,3个Text
文本,加一个质量指数的分布图。
这里重点说下分布图怎么画:
- 首先是一个渐进色的带圆角的矩形,这里不必使用
Rectangle
,可以直接使用LinearGradient
来实现。 - 其次,内部有一个小圆圈标识当前的指数分布在哪。使用
RoundedRectangle
之后,frame
指定宽高相等,就是圆形。 - 最后,使用
ZStack
将二者叠加。
代码如下:
ZStack{
LinearGradient(gradient: Gradient(colors: [Color.green, Color.yellow, Color.white]), startPoint: .leading, endPoint: .trailing).frame(height: 10).cornerRadius(25)
RoundedRectangle(cornerRadius: 50).stroke(lineWidth: 1.75).fill().frame(width: 10, height: 10).foregroundColor(.black).shadow(color: .white, radius: 1, x: 0.0, y: 0.0)
}
五、横向滚动视图
这里是一个横向的视图,而且需要隐藏掉滚动条(默认是显示的)。
ScrollView(.horizontal, showsIndicators: false){
HStack(spacing: 20){
}
}
这里要着重提醒下,默认指定
.horizontal
理论上来说即为横向滚动视图。但是如果不加个HStack
在内部包裹内容,横向不生效,谷歌百度stackoverflow
都没有查到原因,不知道是不是SwiftUI
的bug
,所以在此特地提醒下。
六、封装
这部分内容,还是先考虑布局,红色的纵向布局
VStack
,绿色的横向布局HStack
。
VStack{
ForEach(weeks, id: \.self){week in
HStack{
Text(week).padding(.trailing).padding(.leading)
Spacer()
weathers[Int.random(in: 0..<3)]
Spacer()
Text("\(Int.random(in: 28..<32))")
Spacer()
Text("\(Int.random(in: 22..<38))").foregroundColor(Color(red: 175/255, green: 180/255, blue: 185/255)).padding(.trailing)
}.padding(.bottom, 1.5)
}
}
这里推荐对横向布局内容做一层封装,提升代码的可读性。
创建一个WeekRowView.swift
文件,代码如下:
struct WeekRowView: View {
var week: String
var weather: Image
var maxTemperature: Int
var minTemperature: Int
var body: some View {
HStack{
Text(week).padding(.trailing).padding(.leading)
Spacer()
weather
Spacer()
Text("\(maxTemperature)")
Spacer()
Text("\(minTemperature)").foregroundColor(Color(red: 175/255, green: 180/255, blue: 185/255)).padding(.trailing)
}.padding(.bottom, 1.5)
}
}
然后改造上面代码如下:
VStack{
ForEach(weeks, id: \.self){week in
WeekRowView(week: week, weather: weathers[Int.random(in: 0..<3)], maxTemperature: Int.random(in: 28..<32), minTemperature: Int.random(in: 22..<38))
}
}
这部分同上,不具体描述了。
七、Link
链接
HStack{
Text("昌平区的天气,").foregroundColor(.white)
Link(destination: URL(string: "http://maps.apple.com")!, label: {
Text("在“地图”中打开").underline()
})
}
- 使用
Link
组件,destination
指向链接的地址,可以是网站,也可以是app
。网站会跳转到默认的浏览器打开。 - 下划线使用
.underline
属性即可。
至此,整个天气APP
UI界面的仿写就完成了。