TOP

UIScrollView 和 UICollectionView 分頁效果(一)
2017-10-12 12:02:04 】 瀏覽:11063
Tags:

UIScrollView 和 UICollectionView 分頁效果

UIScrollView可以滾動顯示寬度或高度大于其bounds的內容。有些時候,需要有分頁效果。每一頁有統一的大小,相鄰無縫水平或垂直排列。當水平或垂直滾動松開手后,會在其中一頁完全顯示的位置停下,滾動的距離是一頁寬度或高度的整數倍。具體實現方法分兩種情況討論:分頁大小等于、小于bounds大小。分頁大小大于bounds大小的情況,不知道有什么應用場景,不討論。

分頁大小等于 bounds 大小

如果分頁大小與 bounds 大小相等,把UIScrollViewisPagingEnabled屬性設置為true即可。此屬性的官方解釋

If the value of this property is true, the scroll view stops on multiples of the scroll view’s bounds when the user scrolls.

每一頁的大小為bounds的大小,每次水平或垂直滾動的距離是bounds寬度或高度的整數倍。

分頁大小小于 bounds 大小

UIScrollViewUICollectionView實現的方法不一樣,需要分別討論。

代碼已上傳 GitHub:https://github.com/Silence-GitHub/PageScrollViewDemo

UIScrollView 分頁

UIScrollViewclipsToBounds屬性默認為true,超出bounds的子視圖(超出部分)是看不到的。可以把clipsToBounds設置為false,把isPagingEnabled設置為true,把bounds設置為需要的分頁大小,在視覺上就基本達到分頁效果了。然而优乐棋牌app下载,這樣會出現的問題是:

  1. 滾動條只在bounds以內顯示(所以分頁效果只是視覺上“基本達到”)
  2. UIScrollView顯示的內容會超出所在UIViewControllerview所在范圍,當UINavigationController發生 push 或 pop 時,可能會看到超出部分,不美觀
  3. 觸摸bounds以外的區域沒有響應

對于第 1 個問題,需要隱藏滾動條,把showsVerticalScrollIndicatorshowsHorizontalScrollIndicator都設置為false。既然要分頁效果,滾動條就沒必要顯示。可以用UIPageControl或自定義控件來顯示當前分頁在所有分頁中的位置。非要顯示滾動條的情況不討論。

對于第 2 個問題,可以把當前所在UIViewControllerviewclipsToBounds設置為true;或者把 scroll view 放在另一個UIView上,把這個UIViewclipsToBounds設置為true

對于第 3 個問題,需要重載func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?方法。此方法的官方介紹

Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point.

此方法返回包含觸摸點的最上層視圖(UIView),沒有則返回nil。觸摸屏幕時优乐棋牌app下载,屏幕上的視圖通過此方法尋找發生觸摸的視圖。

Points that lie outside the receiver’s bounds are never reported as hits, even if they actually lie within one of the receiver’s subviews. This can occur if the current view’s clipsToBounds property is set to false and the affected subview extends beyond the view’s bounds.

當觸摸點在bounds之外,此方法返回nil,表示當前視圖不是發生觸摸的視圖。這就是問題的原因。需要自定義UIScrollView,重載此方法,讓此方法在bounds之外觸摸當前視圖也返回被觸摸的視圖。自定義類PageScrollView

class PageScrollView: UIScrollView {
    var interactionAreaNotInBounds: [CGRect] = []