InfiniteScrollViews

InfiniteScrollViews 包含了一些有用的 SwiftUI、UIKit 和 AppKit 组件。

一种递归逻辑

因为我们无法真正生成无限多的视图并将它们放入 ScrollView 中,所以我们需要使用**一种递归逻辑**。InfiniteScrollView 和 PagedInfiniteScrollView 可以显示“无限”内容,这要归功于这种逻辑。

  1. 你有一个泛型类型 **ChangeIndex**,它是组件将提供给你的数据,以换取 View/UIViewController/NSViewController。
  2. 当你初始化组件时,它接受一个 **ChangeIndex** 类型的参数来绘制其第一个视图。
  3. 当用户向上/向下或向左/向右滚动时,组件将给你一个 **ChangeIndex**,但为了获得它的“下一个”或“上一个”值,它将使用初始化期间提供的增加和减少操作。它将用于使用第 1 步中的逻辑绘制“下一个”或“上一个” View/UIViewController/NSViewController。它会一直持续下去,但有一个例外:如果在步骤 3 发生时你返回 nil,它将结束滚动并表现得好像没有更多内容可显示。让我们看一个例子:你想要绘制一个“无限”日历组件,就像 iOS 上的基础日历应用程序中的那样。所有这些都在 SwiftUI 中完成(但它也适用于 UIKit 和 AppKit!)。

示例

  1. 首先让我们看看如何初始化视图
    InfiniteScrollView(
         frame: CGRect,
         changeIndex: ChangeIndex,
         content: @escaping (ChangeIndex) -> Content,
         contentFrame: @escaping (ChangeIndex) -> CGRect,
         increaseIndexAction: @escaping (ChangeIndex) -> ChangeIndex?,
         decreaseIndexAction: @escaping (ChangeIndex) -> ChangeIndex?,
         orientation: UIInfiniteScrollView<ChangeIndex>.Orientation, // or NSInfiniteScrollView<ChangeIndex>.Orientation
         refreshAction: ((@escaping () -> Void) -> ())? = nil,
         spacing: CGFloat = 0,
         updateBinding: Binding<Bool>? = nil
    )
    • frame: InfiniteScrollView 的框架。
    • changeIndex: 用于绘制视图的第一个索引。
    • content: InfiniteScrollView 用来从 ChangeIndex 绘制 View 的查询。
    • contentFrame: InfiniteScrollView 用来从内容查询中获取 View 的框架的查询(它们是分开的,因此你可以直接在闭包中声明 View)。
    • increaseIndexAction: InfiniteScrollView 用来获取某个 ChangeIndex 之后的值的查询(递归逻辑)。
    • decreaseIndexAction: InfiniteScrollView 用来获取某个 ChangeIndex 之前的值的查询(递归逻辑)。
    • orientation: InfiniteScrollView 的方向。
    • refreshAction: 当用户将 InfiniteScrollView 拉到顶部以刷新内容时要执行的操作,如果不需要刷新任何内容,则应为 nil。提供一个必须使用的 action 才能结束刷新。
    • spacing: 视图之间的间距。
    • updateBinding: 如果需要更新 InfiniteScrollView 的内容,则可以更改的布尔值。
  2. 让我们看看 content、increaseIndexAction 和 decreaseIndexAction 如何工作
    1. 对于我们的 MonthView,我们需要提供一个 Date,以便它提取要显示的月份。它可以这样声明
      content: { currentDate in
          MonthView(date: currentDate)
              .padding()
      }
    2. 现在让我们看看增加/减少是如何工作的:要增加,我们需要获取提供的 Date 之后的月份
      increaseIndexAction: { currentDate in
          return Calendar.current.date(byAdding: .init(month: 1), to: currentDate)
      }
      它会将一个月添加到 currentDate,如果操作不成功,则返回 nil,InfiniteScrollView 停止。
    3. 相同的逻辑适用于减少操作
      decreaseIndexAction: { currentDate in
          return Calendar.current.date(byAdding: .init(month: -1), to: currentDate)
      }

可以在 InfiniteScrollViewsExample 中找到其他示例。

SwiftUI

InfiniteScrollView

SwiftUI 中 ScrollView 组件的无限版本。

PagedInfiniteScrollView

SwiftUI 中分页 TabView 组件的无限版本。

UIKit

UIInfiniteScrollView

UIKit 中 UIScrollView 组件的无限版本。

UIPagedInfiniteScrollView

UIKit 中 UIPageViewController 的一个更简单的版本。

AppKit

NSInfiniteScrollView

AppKit 中 NSScrollView 组件的无限版本。

NSPagedInfiniteScrollView

AppKit 中 NSPageController 组件的无限版本。