SwiftUI实战-仿写天气App

3,518 阅读3分钟

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

一、引言

本期实战,仿写iPhone自带的天气APP

image.png

左边是真正的天气App,右边是仿写的。

屏幕录制2021-08-12 22.18.41.gif

二、首要任务-布局

写这个APP首先要考虑的,是整体的布局,比如这个APP,是可以滑动到底的,也就是说内容无法一个页面内全部展开显示,需要通过滑动展示其余的内容。基于此,使用ScrollViewLazyVStack的二人组是必须的。ScrollView可以使页面内容无限制高度;LazyVStack可以优化大量内容的渲染延迟加载,提高性能。

ScrollView{
    LazyVStack{
        //内容如下
    }
}

其次,背景图片要伴随这个滚动视图,先通过ZStack叠加ScrollViewImage,然后调整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)

image.png

四、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)
}

五、横向滚动视图

屏幕录制2021-08-12 22.40.17.gif

这里是一个横向的视图,而且需要隐藏掉滚动条(默认是显示的)。

 ScrollView(.horizontal, showsIndicators: false){
   HStack(spacing: 20){
       
   }
}

这里要着重提醒下,默认指定.horizontal理论上来说即为横向滚动视图。但是如果不加个HStack在内部包裹内容,横向不生效,谷歌百度stackoverflow都没有查到原因,不知道是不是SwiftUIbug,所以在此特地提醒下。

六、封装

image.png 这部分内容,还是先考虑布局,红色的纵向布局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)) 
    }
}

image.png

这部分同上,不具体描述了。

七、Link链接

HStack{
    Text("昌平区的天气,").foregroundColor(.white)
    
    Link(destination: URL(string: "http://maps.apple.com")!, label: {
        Text("在“地图”中打开").underline()
    })
}

  • 使用Link组件,destination指向链接的地址,可以是网站,也可以是app。网站会跳转到默认的浏览器打开。
  • 下划线使用.underline属性即可。

至此,整个天气APP UI界面的仿写就完成了。

附录

代码地址