SwiftUI极简教程24:构建一个Banner图片轮播(上)

简介: SwiftUI极简教程24:构建一个Banner图片轮播(上)

在本章中,你将学会如何构建一个Banner轮播图。

在很多App首页中,我们可以看到在主要视图的顶部位置,常常有一个Banner轮播图的存在,它通过左右滑动图片的形式,展示给用户查看推荐的信息。

在本章中,我们就来实现下如何使用SwiftUI构建一个Banner轮播图。


image.png

那么,让我们开始吧。

首先,创建一个新项目,命名为SwiftUIBanner

image.png

首先,我们先创建基本的卡片视图CardView。我们可以看到它由一张Image图片卡片和Text文字组成,我们先在Assets.xcassets中导入一批图片作为素材使用。

image.png

然后,我们完成下展示一张Image图片卡片,并在ContentView主视图中预览它。


struct CardView: View {
    var body: some View {
        ZStack {
            GeometryReader { geometry in
                Image("image01")
                    .resizable()
                    .scaledToFill()
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    .cornerRadius(15)
                    .overlay(
                        Text("图片01")
                            .font(.system(.headline, design: .rounded))
                            .fontWeight(.heavy)
                            .padding(10)
                            .background(Color.white)
                            .padding([.bottom, .leading])
                            .opacity(1.0)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .bottomLeading)
                    )
            }
        }
    }
}


image.png


这里科普一个知识点。

我们发现代码和以前学习的不同,我们新增了GeometryReader几何容器,将我们的Image图片和Text文字包裹在里面。而且图片的大小.frame修饰符中,设置的Image图片尺寸是我们GeometryReader几何容器宽高。

GeometryReader几何容器简单来说,就是一个View,但不同的是,它的宽高是通过自动判断你的设备的屏幕尺寸的定的。这样,假设我们有一张4000*4000分辨率的图片的时候,我们就不用再设置它在屏幕中展示的固定大小了,屏幕多少,里面的图片就可以自动设置多大。


//GeometryReader使用方法
GeometryReader { geometry in 
    //代码块
}


我们将CardView卡片视图需要展示的内容的变量抽离出来,它是Image图片和Text文字内的内容,用于之后遍历数组模型使用。


let image: String
let imageName: String


下一步,我们定义好我们的Model部分的内容,我们新建一个Swift文件,命名为ImageModel.swift


和之前的章节内容一样,我们定义好包含可被识别的参数的imageModel,当然还有演示的数据数组imageModels


import Foundation
struct imageModel: Identifiable {
    var id = UUID()
    var image: String
    var imageName: String
}
#if DEBUG
let imageModels = [
    imageModel(image: "image01", imageName: "图片01"),
    imageModel(image: "image02", imageName: "图片02"),
    imageModel(image: "image03", imageName: "图片03"),
    imageModel(image: "image04", imageName: "图片04"),
    imageModel(image: "image05", imageName: "图片05"),
    imageModel(image: "image06", imageName: "图片06"),
    imageModel(image: "image07", imageName: "图片07"),
    imageModel(image: "image08", imageName: "图片08"),
    imageModel(image: "image09", imageName: "图片09")
]
#endif


image.png

还记得之前的章节么?我们使用ForEach循环遍历我们定义好的数组内容。

我们这里也尝试下在ContentView主页中显示所有CardView卡片视图的内容。


struct ContentView: View {
    var body: some View {
        GeometryReader { outerView in
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(alignment: .center) {
                    ForEach(imageModels.indices,id:\.self) { index in
                        GeometryReader { innerView in
                            CardView(image: imageModels[index].image, imageName:imageModels[index].imageName)
                        }
                    }
                    .padding(.horizontal, 20)
                    .frame(width: outerView.size.width, height: outerView.size.height)
                }
            }
            .frame(width: outerView.size.width, height: outerView.size.height, alignment: .leading)
        }
    }
}


image.png

这里科普一个知识点。

和之前引用数据数据不同,Xcode 13.3 RC 版本更新了一个内容,我们使用ForEach循环时,由于View是动态生成的,所以id需要指定为id:\.self


ForEach(imageModels.indices,id:\.self) { index in
    //代码块
}


不然Xcode报错


Non-constant range: argument must be an integer literal


这样改动后不仅不会有警告,而且动态创建的View将会通过id来作为唯一标识,需要动态增加和变化的话,不会重复进行创建。

好,我们看回代码本身的内容。

我们在GeometryReader几何容器中使用ScrollViewHStack创建了一个可以左右滑动的视图,然后通过ForEach循环遍历imageModels数组数据,创建了一个个CardView卡片视图。为了更好地根据屏幕大小控制CardView卡片视图大小,我们使用GeometryReader容器的outerView外部视图获取设备屏幕的大小,和innerView内部视图环绕卡片视图来控制其大小。

我们在模拟器中预览下效果。


image.png

这里我们发现一个问题,虽然我们实现了Banner图片轮播的左右滑动,但是滚动视图可以在任何位置停下,这个Banner图片轮播的设计初衷。


那么我们怎样才能让每一个CardView卡片视图能够左右滑动,而且能每次到达一个CardView卡片视图的分页边界时刚好停下来呢?


我们会在后面的章节一一实现。

快来动手试试吧!



相关文章
|
存储 Swift
SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器
在本章中,你将学会使用Segment分段器、LazyVGrid垂直网格、ImagePicker图片选择器构建一个Logo生成器。 在上一章中,我们完善了SearchBar搜索栏、TabView底部导航,还有做了一个Loading加载动作。最近突然有个想法,如果把色卡和图片进行组合,这不就是一个简单的Logo了吗?我能不能做个Logo生成器? 说干就干,我们继续完成App的相关内容。
929 0
SwiftUI极简教程41:使用Segment、LazyVGrid和ImagePicker构建一个Logo生成器
SwiftUI—使用Text视图创建漂亮的富文本
SwiftUI—使用Text视图创建漂亮的富文本
1408 0
SwiftUI—使用Text视图创建漂亮的富文本
|
iOS开发
SwiftUI极简教程34:LazyVGrid垂直网格和LazyHGrid水平网格的使用
SwiftUI极简教程34:LazyVGrid垂直网格和LazyHGrid水平网格的使用
2100 0
SwiftUI极简教程34:LazyVGrid垂直网格和LazyHGrid水平网格的使用
|
程序员 索引
SwiftUI极简教程18:SwipeCard卡片滑动效果的使用(上)
SwiftUI极简教程18:SwipeCard卡片滑动效果的使用(上)
1522 0
SwiftUI极简教程18:SwipeCard卡片滑动效果的使用(上)
|
存储 索引
SwiftUI极简教程19:SwipeCard卡片滑动效果的使用(下)
SwiftUI极简教程19:SwipeCard卡片滑动效果的使用(下)
903 0
SwiftUI极简教程19:SwipeCard卡片滑动效果的使用(下)
|
索引
SwiftUI极简教程26:构建一个Banner图片轮播(下)
SwiftUI极简教程26:构建一个Banner图片轮播(下)
985 0
SwiftUI极简教程26:构建一个Banner图片轮播(下)
|
iOS开发
加载中,加载中......使用SwiftUI设计2种Loading动画
加载中,加载中......使用SwiftUI设计2种Loading动画
854 0
|
Swift iOS开发 容器
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(一)(3)
实战编程·使用SwiftUI从0到1完成一款iOS笔记App(一)
446 0
|
存储 索引
SwiftUI极简教程12:List列表和ForEach循环的使用
SwiftUI极简教程12:List列表和ForEach循环的使用
1471 0
SwiftUI极简教程12:List列表和ForEach循环的使用
|
存储 前端开发 数据安全/隐私保护
SwiftUI极简教程31:Combine异步编程框架和MVVM开发模式的使用(下)
SwiftUI极简教程31:Combine异步编程框架和MVVM开发模式的使用(下)
1345 0
SwiftUI极简教程31:Combine异步编程框架和MVVM开发模式的使用(下)