实现效果
Model
struct Landmark: Identifiable {
var id = UUID()
var name: String
var park: String
var imageName: String
var image: Image {
Image(imageName)
}
}
let datas = [
Landmark(name: "Turtle Rock", park: "Joshua Tree National Park", imageName: "turtlerock_feature"),
Landmark(name: "St.Mary Lake", park: "Glacier National Park", imageName: "stmarylake_feature"),
Landmark(name: "Charley Rivers", park: "Charley Rivers National Preserve", imageName: "charleyrivers_feature")
]
Card
struct Card: View {
var landmark: Landmark
var body: some View {
landmark.image
.resizable()
.aspectRatio(1.5, contentMode: .fit)
.overlay(TextOverlay(landmark: landmark))
}
}
struct Card_Previews: PreviewProvider {
static var previews: some View {
Card(landmark: datas[0])
}
}
struct TextOverlay: View {
var landmark: Landmark
var gradient: LinearGradient {
LinearGradient(
gradient: Gradient(
colors: [Color.black.opacity(0.6), Color.black.opacity(0)]),
startPoint: .bottom,
endPoint: .center)
}
var body: some View {
ZStack(alignment: .bottomLeading) {
Rectangle()
.fill(gradient)
VStack(alignment: .leading) {
Text(landmark.name)
.foregroundColor(.white)
.font(.title)
.bold()
Text(landmark.park)
.foregroundColor(.white)
}
.padding()
}
}
}
简单的图片和文字结合的卡牌。
PageController
struct PageViewController: UIViewControllerRepresentable {
// 轮播控制器当前页
@Binding var currentPage: Int
var controllers: [UIViewController]
// 创建协调器
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
// 创建controller
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
// 协调器遵守协议
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
return pageViewController
}
// 更新controller
func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {
uiViewController.setViewControllers([controllers[currentPage]], direction: .forward, animated: true, completion: nil)
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PageViewController
init(_ pageViewController: PageViewController) {
parent = pageViewController
}
// MARK: - UIPageViewControllerDataSource
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
// 如果是第一个,返回最后一个
if index == 0 {
return parent.controllers.last
}
return parent.controllers[index - 1];
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
// 如果是最后一个,返回第一个
if index + 1 == parent.controllers.count {
return parent.controllers.first
}
return parent.controllers[index + 1];
}
// MARK: - UIPageViewControllerDelegate
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if
completed,
let viewController = pageViewController.viewControllers?.first,
let index = parent.controllers.firstIndex(of: viewController) {
parent.currentPage = index
}
}
}
}
在SwiftUI中使用UIKit中的ViewController需要实现UIViewControllerRepresentable
协议,实现makeUIViewController
和updateUIViewController
方法。使用协调器Coordinator
来实现控制器的数据源和代理。通过context.coordinator
来实现UIKit与SwiftUI的整合。
PageView
struct PageView<Page: View>: View {
@State var currentPage: Int = 0
var viewControllers: [UIHostingController<Page>]
// 初始化方法,利用SwiftUI视图创建UIHostingController
init(_ views: [Page]) {
self.viewControllers = views.map { UIHostingController(rootView: $0) }
}
var body: some View {
ZStack(alignment: .bottomTrailing) {
PageViewController(currentPage: $currentPage, controllers: viewControllers)
PageControl(numberOfPages: viewControllers.count, currentPage: $currentPage)
.frame(width: CGFloat(viewControllers.count * 18))
.padding()
}
}
}
struct PageView_Previews: PreviewProvider {
static var previews: some View {
PageView(datas.map { Card(landmark: $0) })
}
}
通过传入SwiftUI的Views利用整合的PageViewController创建轮播器,PageView为可以供SwiftUI视图调用的视图。PageView向PageViewController和PageControl传递currentPage
属性来实现图片和小圆点的切换,同样他们通过绑定currentPage
属性完成修改。
PageControl
struct PageControl: UIViewRepresentable {
var numberOfPages: Int
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UIPageControl {
let control = UIPageControl()
control.numberOfPages = numberOfPages
control.addTarget(context.coordinator, action: #selector(Coordinator.updateCurrentPage(sender:)), for: .valueChanged)
return control
}
func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
}
class Coordinator: NSObject {
var parent: PageControl
init(_ pageControl: PageControl) {
parent = pageControl
}
// pageControl触发事件
@objc func updateCurrentPage(sender: UIPageControl) {
parent.currentPage = sender.currentPage
}
}
}
UIKit的UIView类视图需要实现UIViewRepresentable
协议,与UIViewControllerRepresentable
协议使用方法相同。