SwipeView 1.3.2

SwipeView 1.3.2

测试已测试
语言语言 Obj-CObjective C
许可 zlib
发布上次发布2014年12月

Nick Lockwood维护。



SwipeView 1.3.2

  • 作者:
  • Nick Lockwood

目的

SwipeView是一个用于简化在iOS上实现横向、分页滚动视图的类。它基于UIScrollView,但添加了如动态加载数据源/委托界面的TableView样式,以及高效视图加载、unload和回收等便捷功能。

SwipeView的接口和实现基于iCarousel库,对使用过iCarousel的用户来说应该很熟悉。

支持的操作系统和SDK版本

  • 支持的构建目标是iOS 7.0(Xcode 5.0,Apple LLVM编译器5.0)
  • 最早支持的部署目标是iOS 5.0
  • 最早兼容的部署目标是iOS 4.3

注:'支持'表示该库已经与该版本进行过测试。'兼容'表示该库应该在操作系统版本上运行(即它不依赖于任何不可用的SDK功能),但不再进行兼容性测试,可能需要调整或修复错误才能正确运行。

ARC兼容性

从版本1.3开始,SwipeView需要ARC。如果您希望在一个非ARC项目中使用SwipeView,只需将-fobjc-arc编译器标志添加到SwipeView.m类中。要做到这一点,请转到目标设置中的构建设置选项卡,打开编译源文件组,在列表中双击SwipeView.m,并在弹出窗口中键入-fobjc-arc。

如果您想将整个项目转换为ARC,请在SwipeView.m中取消注释#error行,然后运行Xcode中的编辑 > 重构 > 转换为Objective-C ARC...工具,并确保所有希望使用ARC的文件都已被选中(包括SwipeView.m)。

线程安全性

SwipeView是从UIView派生来的,就像所有的UIKit组件一样,它应该只从主线程访问。您可能会想使用线程来加载数据或更新SwipeView的内容或项,但始终确保内容加载后,您在更新SwipeView之前切换回主线程。

安装

要在一个应用程序中使用SwipeView类,只需将SwipeView类文件(不需要demo文件和资源)拖放到您的项目中。

属性

SwipeView具有以下属性

@property (nonatomic, weak) IBOutlet id<SwipeViewDataSource> dataSource;

支持SwipeViewDataSource协议的对象,可以提供视图来填充SwipeView。

@property (nonatomic, weak) IBOutlet id<SwipeViewDelegate> delegate;

支持SwipeViewDelegate协议的对象,可以响应SwipeView事件和布局请求。

@property (nonatomic, readonly) NSInteger numberOfItems;

SwipeView中的项目数量(只读)。要设置此属性,请实现dataSource的numberOfItemsInSwipeView:方法。请注意,并非所有这些项目视图将在某个特定时间点被加载或显示 - SwipeView在滚动时按需加载项目视图。

@property (nonatomic, readonly) NSInteger numberOfPages;

SwipeView中的页数(只读)。要设置此属性,请实现numberOfItemsInSwipeView: dataSource方法,并设置itemsPerPage值。如果itemsPerPage = 1,则numberOfPages将与numberOfItems相匹配。

@property (nonatomic, readonly) CGSize itemSize;

SwipeView中每个项目的尺寸。该属性为只读,但可以使用swipeViewItemSize: delegate方法进行设置。

@property (nonatomic, assign) NSInteger itemsPerPage;

启用分页时每页的项目数量。默认值为一个。

@property (nonatomic, assign) BOOL truncateFinalPage;

如果项目数量不能被itemsPerPage值整除,则最后可能会有空白空间。通过将truncateFinalPage设置为YES,可以消除该空间。

@property (nonatomic, strong, readonly) NSArray *indexesForVisibleItems;

包含当前在SwipeView中加载和可见的所有项目视图索引的数组。数组包含与视图索引匹配的NSNumber对象。项目视图的索引从零开始,并匹配发送给dataSource以加载视图的索引。

@property (nonatomic, strong, readonly) NSArray *visibleItemViews;

当前在SwipeView中显示的所有项目视图的数组(只读)。此数组中视图的索引不与项目索引匹配,但视图的顺序与visibleItemIndexes属性数组的顺序匹配,即您可以通过检索此数组中等效的对象来获取给定视图的项目索引(或者,您也可以使用indexOfItemView:方法,这要容易得多)。

@property (nonatomic, strong, readonly) UIView *currentItemView;

当前显示的页面中中心(或左对齐,取决于对齐值)的第一个项目视图。

@property (nonatomic, readonly) NSInteger currentItemIndex;

当前显示的页面中中心(或左对齐,取决于对齐值)的第一个项目的索引。设置此值等效于带有duration参数设置为0.0的调用scrollToItemAtIndex:duration:

@property (nonatomic, assign) NSInteger currentPage;

当前显示的页面中中心(或左对齐,取决于对齐值)的页面的索引。如果itemsPerPage等于一个,则此值将匹配currentItemIndex值。设置此值等效于带有duration参数设置为0.0的调用scrollToPage:duration:

@property (nonatomic, assign) SwipeViewAlignment alignment;

此属性控制SwipeView项目的对齐方式。默认值为SwipeViewAlignmentEdge,表示项目视图将延伸到SwipeView的边缘。将对齐切换到SwipeViewAlignmentCenter表示当SwipeView完全滚动到极端时,最左端和最右端的项目视图将居中。

@property (nonatomic, assign, getter = isPagingEnabled) BOOL pagingEnabled;

启用和禁用分页。启用分页时,当用户滚动时,SwipeView将停在每个项目视图上。

@property (nonatomic, assign, getter = isScrollEnabled) BOOL scrollEnabled;

启用和禁用SwipeView的用户滚动。如果此属性设置为NO,SwipeView仍然可以以编程方式进行滚动。

@property (nonatomic, assign, getter = isWrapEnabled) BOOL wrapEnabled;

启用和禁用环绕。在环绕模式下,SwipeView可以无限滚动,并且当它越过最后一个项目视图时将环绕到第一个项目视图。启用环绕时,bounces属性将没有效果。

@property (nonatomic, assign, getter = isVertical) BOOL vertical;

此属性切换SwipeView在屏幕上水平还是垂直显示。

@property (nonatomic, assign) BOOL delaysContentTouches;

此属性与UIScrollView的等效属性类似。它将SwipeView内部子视图的触摸事件处理延迟,以便嵌入的控制(如按钮)不会干扰SwipeView的平滑滚动。默认为YES。

@property (nonatomic, assign) BOOL bounces;

设置SwipeView是否应该反弹超过结束并返回,或者直接停止。

@property (nonatomic, assign) float decelerationRate;

一个浮点值,用于确定用户抬起手指后的减速率。

@property (nonatomic, readonly, getter = isDragging) BOOL dragging;

返回YES,如果用户已经开始滚动SwipeView,但尚未释放。

@property (nonatomic, readonly, getter = isDecelerating) BOOL decelerating;

返回YES,如果用户不再拖动SwipeView,但依旧在移动。

@property (nonatomic, readonly, getter = isScrolling) BOOL scrolling;

如果 SwipeView 当前正在程序化滚动,返回 YES。

@property (nonatomic, assign) BOOL defersItemViewLoading;

有时当 SwipeView 包含非常复杂的项视图或大图像时,在加载新视图时可能会出现明显的滚动性能卡顿。将 defersItemViewLoading 属性设置为 YES 将强制 SwipeView 在滚动完成后才更新 currentItemIndex 属性和加载新项视图。如果一次性滚动得太远,这可能导致 SwipeView 出现可见的空隙,但对于短距离滚动,您可能会发现这可以改善动画性能。

@property (nonatomic, assign) CGFloat autoscroll;

此属性可以用来设置 SwipeView 以恒定速度滚动。值为 1.0 时,每秒将滚动一个项目。自动滚动值可以是正数或负数,默认为 0.0(静止)。如果用户与 SwipeView 进行交互,自动滚动将停止,并在他们停止交互时继续。

方法

SwipeView 类有以下方法

- (void)reloadData;

这将重新从 dataSource 加载所有 SwipeView 项视图并刷新显示。请注意,reloadData 将将 currentItemIndex 重置为零,因此如果您想保留当前滚动位置,请在重新加载之前记下 currentItemIndex,并在之后恢复它。如果您只想刷新可见的项目而不是更改项目数量,请考虑在所有可见项目中调用 reloadItemAtIndex:

- (void)reloadItemAtIndex:(NSInteger)index;

此方法将重新加载指定的项视图。新项将根据 dataSource 请求。屏幕外的视图不会被重新加载。

- (void)scrollByNumberOfItems:(NSInteger)itemCount duration:(NSTimeInterval)duration;

此方法允许通过固定的距离滚动 SwipeView,距离以项目宽度计算。可以根据所需的滚动方向指定 itemCount 的正数或负数值。SwipeView 优雅地处理边界问题,因此如果您指定的距离大于 SwipeView 中项目数量,则当滚动到 SwipeView 的末端时会受到限制。

- (void)scrollToItemAtIndex:(NSInteger)index duration:(NSTimeInterval)duration;

此操作会将 SwipeView 中心对齐到指定的项,要么立即对齐,要么使用平滑动画对齐。

- (void)scrollToPage:(NSInteger)page duration:(NSTimeInterval)duration;

此操作会将 SwipeView 中心对齐到指定的项,要么立即对齐,要么使用平滑动画对齐。

- (UIView *)itemViewAtIndex:(NSInteger)index;

返回具有指定索引的可见项视图。请注意,索引与 SwipeView 中的位置相关,而不是与 visibleItemViews 数组中的位置相关,这可能是不同的。此方法仅适用于可见项视图,如果指定的索引视图尚未加载,或索引超出范围,则返回 nil。

- (NSInteger)indexOfItemView:(UIView *)view;

SwipeView 中给定项视图的索引。此方法仅适用于可见项视图,对于尚未加载的视图将返回 NSNotFound。要获取已加载的所有视图的列表,请使用 visibleItemViews 属性。

- (NSInteger)indexOfItemViewOrSubview:(UIView *)view

此方法为您提供传递的视图或包含传递的视图作为参数的视图的项索引。这是通过从传递的视图开始逐层上溯视图层次结构,直到找到项视图,并返回其在 SwipeView 中的索引来实现的。如果没有找到当前加载的项视图,它返回 NSNotFound。该方法对于处理嵌入在项视图中的控制事件非常有用。这使得您可以将所有项控件绑定到您的视图控制器的一个操作方法上,然后确定触发动作的控制相关联的项。

协议

SwipeView 遵循 Apple 为数据驱动视图提供的两个协议接口的约定,即 SwipeViewDataSource 和 SwipeViewDelegate。SwipeViewDataSource 协议有以下必要方法

- (NSInteger)numberOfItemsInSwipeView:(SwipeView *)swipeView;

返回 SwipeView 中的项目(视图)数量。

- (UIView *)swipeView:(SwipeView *)swipeView viewForItemAtIndex:(NSInteger)index reusingView:(UIView *)view;

返回一个视图,在SwipeView中显示指定索引。参数reusingView的工作原理类似于 UIPickerView,以前在SwipeView中显示的视图会被传递回该方法进行回收。如果这个参数不为nil,你可以设置它的属性并返回它,而不是创建一个新的视图实例,这可以略微提高性能。与UITableView不同,SwipeView没有reuseIdentifier来区分不同的视图类型,所以如果你的SwipeView包含多种不同的视图类型,你应该忽略这个参数,并在每次调用该方法时返回一个新的视图。你应该确保每次调用swipeView:viewForItemAtIndex:reusingView:方法时,要么返回reusingView,要么返回一个新的视图实例,而不是维护自己的回收视图池,因为为不同的SwipeView项索引返回相同视图的多个副本可能会引起SwipeView显示问题。

SwipeViewDelegate协议有以下可选方法

- (CGSize)swipeViewItemSize:(SwipeView *)swipeView;

返回每个项视图的大小(以点/像素为单位)。如果不实现此方法,则自动从加载的第一个项视图计算项大小。

- (void)swipeViewDidScroll:(SwipeView *)swipeView;

每次SwipeView滚动时都会调用此方法。无论SwipeView是程序化滚动还是通过用户交互滚动,都会调用此方法。

- (void)swipeViewCurrentItemIndexDidChange:(SwipeView *)swipeView;

每次SwipeView滚动足够远,使得currentItemIndex属性发生变化时,都会调用此方法。无论项索引是程序化更新还是通过用户交互更新,都会调用此方法。

- (void)swipeViewWillBeginDragging:(SwipeView *)swipeView;

用户开始拖动SwipeView时,会调用此方法。

- (void)swipeViewDidEndDragging:(SwipeView *)swipeView willDecelerate:(BOOL)decelerate;

用户停止拖动SwipeView时,会调用此方法。willDecelerate参数表示SwipeView是否以足够快的速度移动,需要减速后停止(即当前索引不一定是它将停止的位置),或者如果它会停在当前位置。注意,即使willDecelerate为NO,如果启用分页,SwipeView仍会自动滚动,直到它与当前索引对齐。

- (void)swipeViewWillBeginDecelerating:(SwipeView *)swipeView;

用户完成拖动SwipeView后,会开始减速,会调用此方法。

- (void)swipeViewDidEndDecelerating:(SwipeView *)swipeView;

SwipeView完成减速后调用此方法,此时可以假设currentItemIndex的值是这个最终的停止值。

- (void)swipeViewDidEndScrollingAnimation:(SwipeView *)swipeView;

程序化滚动后,SwipeView完成移动时调用此方法,使用的方法是scrollByNumberOfItems:scrollToItemAtIndex:

- (void)swipeView:(SwipeView *)swipeView didSelectItemAtIndex:(NSInteger)index;

如果用户在SwipeView中点击任何项视图,将触发此方法。如果用户在当前选中视图内点击(即任何UIControl的子类),则不会触发此方法。

- (BOOL)swipeView:(SwipeView *)swipeView shouldSelectItemAtIndex:(NSInteger)index;

如果用户在SwipeView中点击任何项视图,将触发此方法。该方法的目的为给你提供一个忽略SwipeView点击的机会。如果你从方法中返回YES,或不实现它,则点击将被正常处理,并调用swipeView:didSelectItemAtIndex:方法。如果你返回NO,SwipeView将忽略点击,并将事件继续向上传递视图层级。这是一种防止SwipeView拦截其他视图处理点击事件的好方法。

检测项视图的点击

检测SwipeView中视图点击有两种基本方法。第一种方法是简单使用swipeView:didSelectItemAtIndex:委托方法,它会在点击任何项时触发。

或者,如果您需要更多控制,您可以将UIButton或UIControl作为项视图提供,并自行处理触摸交互。

您也可以在项视图中嵌套UIControls,这些控件将以预期的方式接收触摸(请参阅Controls示例项目,了解如何这么做)。

如果您想检测其他类型的交互,如滑动、双击或长按,最简单的方法是在将项目视图或其子视图传递给SwipeView之前,将其附加到UIGestureRecognizer。

发行说明

版本 1.3.2

  • 当SwipeView缩放或旋转时,现在正确计算滚动偏移量
  • 撤销了1.3.1中的修复,因为它导致了更糟糕的其他滚动偏移量问题

版本 1.3.1

  • 修复了旋转屏幕时滚动偏移量变化的问题

版本 1.3

  • SwipeView现在需要ARC(请参阅README以获取详细信息)
  • 添加了自动滚动属性来设置SwipeView以恒定速度滚动
  • 现在支持动画项目视图大小调整和屏幕旋转
  • 不再在某些iOS 7版本上崩溃
  • scrollOffset属性现在是公开的
  • 添加了scrollByOffset:duration:和scrollToOffset:duration:方法
  • 调用reloadData不再重置滚动位置
  • 如果只有一个项目并且启用了wrap,则不再出现奇怪的行为
  • 修复了在UINavigationController中使用contentOffset时的问题
  • 现在可以在不影响项目视图的情况下随时切换wrapEnabled
  • 现在符合-Weverything警告级别

版本 1.2.10

  • 固定了SwipeView动画和UIScrollView滚动之间的冲突问题
  • 解决由于缺少[super layoutSubviews]导致的错误

版本 1.2.9

  • 修复了启用wrap时点击处理的问题

版本 1.2.8

  • 修复了swipe视图大小为零时的边界错误
  • 修复了自动计算项目大小逻辑中的错误
  • 修复了在非包裹模式下有时不绘制最后一个可见视图的问题
  • 将ARCHelper宏从.h文件中移除,以便它们不会影响其他类中非ARC代码

版本 1.2.7

  • numberOfItems / numberOfPages获取器现在调用numberOfItemsInSwipeView: dataSource方法以确保值的正确性。

版本 1.2.6

  • SwipeView现在能更精确地计算可见视图的数量
  • 修复了wrapEnabled = YES且alignment = SwipeViewAlignmentEdge时可能引起的空隙问题时的问题
  • SwipeView直到需要绘制视图时才尝试调用任何dataSource方法,从而避免某些竞争条件

版本 1.2.5

  • 修复了在启用defersItemViewLoading选项时SwipeView未能正确延迟视图加载的问题

版本 1.2.4

  • SwipeView现在正确处理了当前页面边界之外的视图的触摸事件
  • 在启用defersItemViewLoading时,修复了舍入错误
  • 添加了Control示例来演示触摸事件处理

版本 1.2.3

  • 修复了创建SwipeView后立即设置currentItemIndex会阻止用户向左滑动的问题

版本 1.2.2

  • 修复了启用分页时边缘对齐的SwipeView的舍入错误

版本 1.2.1

  • 修复了使用scrollToItemAtIndex:duration:方法时的偏移量错误
  • 当启用defersItemViewLoading时,swipeViewDidScroll:事件现在被发送为正常,但swipeViewCurrentItemIndexDidChange:仍然被延迟

版本 1.2

  • 添加了垂直滚动选项
  • 将itemWidth属性和swipeViewItemWidth:代理方法更改为itemSize和swipeViewItemSize:
  • 修复了启用defersItemViewLoading时的一些错误

版本 1.1.7

  • 添加了delaysContentTouches属性,默认为YES
  • 修复了使用defersItemViewLoading时的空白页面问题

版本 1.1.6

  • 现在在滑动以及程序滚动时也会监视defersItemViewLoading属性
  • 修复了除以零错误

版本 1.1.5

  • 修复了一次滚动多个页面时的布局错误
  • 添加了defersItemViewLoading属性

版本 1.1.4

  • 滚动方法现在允许您指定滚动持续时间

版本 1.1.3

  • 修复了包裹SwipeView上的重新加载错误
  • 添加了测试项目文件夹

版本 1.1.2

  • 修复了轮播图中特定项目数量导致的换行问题
  • 现在在轮播图上调用 reloadData 将重置 currentItemIndex 为零

版本 1.1.1

  • 移除了一些遗留的断言代码,这些代码破坏了视图回收逻辑
  • 修复了在加载后立即调用 SwipeView 滚动而导致崩溃的 Bug
  • 添加了 ARC 测试示例

版本 1.1

  • 添加了循环播放的支持
  • 现在可以每页显示多个项目
  • 修复了视图旋转或调整大小时出现的布局问题
  • 添加了额外的属性和代理方法
  • 在示例应用程序中添加了分页控件

版本 1.0.1

  • 修复了代理设置方法中的 Bug
  • 修复了当项目总数少于可见数量时崩溃的问题

版本 1.0

  • 添加了动态视图加载和回收功能
  • 添加了 ARC 支持功能
  • 添加了文档说明
  • 重命名了一些方法,以保证与 iCarousel 一致

版本 0.9

  • 预发布版本。