实战编程·刻在男人DNA里的浪漫,空气投篮(一)

简介: 实战编程·刻在男人DNA里的浪漫,空气投篮(一)

实战编程·刻在男人DNA里的浪漫,空气投篮(一)


项目背景

和往常一样的下午,午后的阳光洒在身上,感觉有些舒服。突然脑海里闪过一个念头,小步快跑,起身,双手举起,目视前方,挥手投篮,唰.........最近一款APP几乎引起了所有男孩子的兴趣,这就是空气投篮。

想起年少时和一群朋友走在路上,男孩子们都或多或少做过这种“傻傻的”动作,那是青春的味道。

而竟然有家公司将它做了出来,一时间马上下载、安装.......额.......这.......需要AppleWatch才能用。好吧,竟然没有办法体验空气投篮,不如就用用自己的专长,画画iOS端的页面吧。

项目搭建

首先打开Xcode,创建一个新的SwiftUI项目,命名为AirBall,如下图所示:

image.png

空气投篮分为iOS端和Watch,本章我们先来完成iOS的相关页面。iOS端页面操作及其流程如下图所示:

image.png

实战编程

准备游戏视图

首先是准备游戏视图,简单分析可知,它由文字Text和图片Image组成,背景颜色填充为黑色。Image图片部分,需要导入一张SVG适量图片,使得其很好地与背景融合。如下图所示:

image.png

导入完成后,我们来构建页面部分。在ContentView文件中,我们键入以下代码:

// 准备游戏
func prepareView() -> some View {
  VStack(alignment: .center, spacing: 80) {
    Spacer()
    Text("请确定你已启用Apple Watch上的空气投篮App")
    .font(.system(size: 17))
    .foregroundColor(.white)
    .lineLimit(2)
    .lineSpacing(15)
    .multilineTextAlignment(.center)
    Image("watch_application")
    .resizable()
    .aspectRatio(contentMode: .fit)
    Spacer()
    Spacer()
  }.frame(maxWidth: Constants.screenWidth / 2)
}

上述代码中,我们创建了一个新的View视图prepareView准备开始游戏视图。

在prepareView视图中,文字Text和Image图片使用VStack垂直布局容器包裹,并设置其对齐方式为居中对齐,容器内容元素间距为80。

Text文字部分的处理为设置font字体为17号字,设置foregroundColor填充色为白色,由于文字过长可能导致页面无法展示的原因,这里设置lineLimit文字显示行数为2行,并设置换行时multilineTextAlignment文字对齐方式为居中对齐。

Image图片部分,设置resizable图片缩放,并设置aspectRatio保持原本的宽高比避免变形。

最后使用frame设置VStack垂直布局容器的宽度,为屏幕宽度的一半。为了增强用户体验,在VStack垂直布局容器中使用Spacer占位符,下方设置2个,上方设置一个,这个视觉元素就会展示在屏幕上部分2/3的位置,又是一个小技巧。

完成后,我们在Body中展示,如下代码所示:


ZStack {
  Color(.black).edgesIgnoringSafeArea(.all)
  prepareView()
}

image.png

上述代码中,我们使用ZStack叠加视图,将prepareView准备游戏视图和Color颜色叠加,颜色部分使用edgesIgnoringSafeArea忽略全部安全区域,便可让黑色背景铺满整个屏幕。

游戏列表视图

打开App,进入准备游戏视图,此时需要与Watch端联动,在Watch端确认后,iOS端将进入至游戏列表页面。

image.png

游戏列表页面的交互逻辑是,点击游戏卡片则进入到游戏中,在游戏列表页左右滑动可切换游戏。

我们先来完成单张游戏卡片的设计。分析得知,单张游戏卡片的内容包括3块内容:游戏项目、游戏说明、游戏封面。

我们创建一个新的视图,代码如下所示:

// MARK: 游戏项
struct gameRowView: View {
    var gameName: String
    var gameHelpText: String
    var gameImage: String
    var body: some View {
        VStack(alignment: .center, spacing: 60) {
            Text(gameName)
                .font(.system(size: 48))
                .bold()
                .foregroundColor(.white)
            VStack(alignment: .center, spacing: 10) {
                Text(gameHelpText)
                    .font(.system(size: 17))
                    .foregroundColor(.white)
                Image(gameImage)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(maxHeight:UIScreen.main.bounds.size.width - 20)
            }
        }
    }
}

上述代码中,我们创建了一个新的结构体gameRowView游戏项视图。

之所以创建一个新的结构体,而没有和上面prepareView准备游戏视图一样直接定义View视图,是因为我们需要将gameRowView游戏项视图作为“母版”,然后按照单个gameRowView游戏项视图构建多个一样样式的游戏卡片。

在gameRowView游戏项视图中,我们声明了3个String类型的变量:gameName游戏名称、gameHelpText游戏说明、gameImage游戏封面。

然后在其Body中创建样式,由于游戏名称的Text和其余两块在页面上还是有些距离,这里使用了2个VStack垂直布局容器,将游戏说明和游戏封面放在一个容器中,它们直接的间距为10,而再用一个VStack垂直布局容器再把游戏标题包裹在一起,间距为60。

这里额外再补充一个知识点。

就是游戏封面使用frame设置其大小的问题,由于我们导入的游戏封面图片可能存在大小不一致的问题,因此如果需要让这个游戏卡片看起来元素位置保持一致,由于使用了VStack垂直布局容器,因此,可以设置图片maxHeight高度为屏幕width宽度,再减去20留点边距。

这样做,无论图片尺寸是多少,每个游戏卡片展示的游戏名称、游戏说明、游戏封面的位置就保持一致了。

我们导入两张SVG格式的游戏图片作为素材使用,如下图所示:

image.png

游戏卡片是左右滑动切换的交互,这时我们就可以在ContentView视图中再创建一个View视图构建它,如下代码所示:


// 游戏列表
func gameListView() -> some View {
  TabView {
      gameRowView(gameName: "投篮", gameHelpText: "手举球开始游戏", gameImage: "basketball")
      gameRowView(gameName: "打棒球", gameHelpText: "双手挥动开始游戏", gameImage: "baseball")
    }
  .tabViewStyle(PageTabViewStyle())
}

image.png

image.png

上述代码中,我们创建了一个游戏列表视图gameListView。

然后使用TabView滚动视图容器包裹了2个gameRowView游戏项视图,游戏项视图中我们给声明的变量赋值以显示内容。最后设置TabView滚动视图的样式,为PageTabViewStyle分页滚动类型,如此便实现了横向切换游戏卡片的交互。

本章代码

为方便学习,本章完整代码如下所示:


import SwiftUI
struct ContentView: View {
    var body: some View {
        ZStack {
            Color(.black).edgesIgnoringSafeArea(.all)
            gameListView()
        }
    }
    // 准备游戏
    func prepareView() -> some View {
        VStack(alignment: .center, spacing: 80) {
            Spacer()
            Text("请确定你已启用Apple Watch上的空气投篮App")
                .font(.system(size: 17))
                .foregroundColor(.white)
                .lineLimit(2)
                .lineSpacing(15)
                .multilineTextAlignment(.center)
            Image("watch_application")
                .resizable()
                .aspectRatio(contentMode: .fit)
            Spacer()
            Spacer()
        }.frame(maxWidth: UIScreen.main.bounds.size.width / 2)
    }
    // 游戏列表
    func gameListView() -> some View {
        TabView {
            gameRowView(gameName: "投篮", gameHelpText: "手举球开始游戏", gameImage: "basketball")
            gameRowView(gameName: "打棒球", gameHelpText: "双手挥动开始游戏", gameImage: "baseball")
        }
        .tabViewStyle(PageTabViewStyle())
    }
}
// MARK: 游戏项
struct gameRowView: View {
    var gameName: String
    var gameHelpText: String
    var gameImage: String
    var body: some View {
        VStack(alignment: .center, spacing: 60) {
            Text(gameName)
                .font(.system(size: 48))
                .bold()
                .foregroundColor(.white)
            VStack(alignment: .center, spacing: 10) {
                Text(gameHelpText)
                    .font(.system(size: 17))
                    .foregroundColor(.white)
                Image(gameImage)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(maxHeight: UIScreen.main.bounds.size.width - 20)
            }
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

本章小结

首先恭喜你,完成了本章的介绍的所有内容!

空气投篮iOS端的页面目前我们只完成了前2张,接下来,我们将继续完成其余的页面及其交互,以及后面也会切换到Watch端,完成空气投篮Watch端的相关页面设计。

总的来说,空气投篮App的页面及其交互并不复杂。

这个项目很小,却实实在在戳中了很多用户的内心。仿佛某些个人“很傻”的小习惯被大众所认知、所接受,这种满足感刚好刺激到了某个痛点,很小,但很痛。

这可能就是一款好的产品的象征,也应该是每个提供产品服务的企业所追求的。

望共勉之~


相关文章
|
传感器 前端开发 iOS开发
实战编程·刻在男人DNA里的浪漫,空气投篮(二)(4)
实战编程·刻在男人DNA里的浪漫,空气投篮(二)
64 1
|
存储 Go iOS开发
实战编程·刻在男人DNA里的浪漫,空气投篮(二)(2)
实战编程·刻在男人DNA里的浪漫,空气投篮(二)
55 1
|
存储
实战编程·刻在男人DNA里的浪漫,空气投篮(二)(1)
实战编程·刻在男人DNA里的浪漫,空气投篮(二)
58 1
|
容器
实战编程·刻在男人DNA里的浪漫,空气投篮(二)(3)
实战编程·刻在男人DNA里的浪漫,空气投篮(二)
51 0
|
程序员 决策智能
博弈论(一)——产品小哥哥的民主妙计
博弈论(一)——产品小哥哥的民主妙计
89 0
|
机器学习/深度学习 存储 缓存
蓝桥杯十大常见天阶功法——音之呼吸.肆之型.模拟
蓝桥杯十大常见天阶功法——音之呼吸.肆之型.模拟
150 0
蓝桥杯十大常见天阶功法——音之呼吸.肆之型.模拟
|
机器学习/深度学习 存储 人工智能
『程序员对联』抽取你的专属新春对联
新春这个文章说实话,经历了蛮多的,一开始其实我是想用`three.js`做个老虎的,但是呢,失败了。废了好几个小时才搞出来两个`虎爪`,害,都怪我`three.js`的能力连基本上手都算不上,没咋玩明白,下次一定给大家做点好康的~
|
前端开发 JavaScript
【中秋】模拟太阳系行星的公转
【中秋】模拟太阳系行星的公转
200 0
【中秋】模拟太阳系行星的公转
|
大数据
NBA球星是如何投篮的?把詹姆斯、库里的投篮数据图3D打印出来
2017-2018的NBA赛季已经落幕。虽然勇士夺冠的结果没有出乎太多人的意料,但是一些扣人心弦的戏码还是令人印象深刻。
2000 0