如何在 UICollectionView Image Scrolling 中添加 PageControl
How to add PageControl inside UICollectionView Image Scrolling
我有 UICollectionView
个水平图像列表代码。我想在显示滚动图像时添加 PageControl
,我添加了 pagecontrol 选择器和 IBOutlet
但如何将它集成到 UICollecitonView
之间?
我的代码如下:
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet weak var View : DesignableView!
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var collectionViewLayout: UICollectionViewFlowLayout!
@IBOutlet open weak var pageControl: UIPageControl? {
didSet {
pageControl?.addTarget(self, action: #selector(ViewController.pageChanged(_:)), for: .valueChanged)
}
}
override func viewDidLoad() {
super.viewDidLoad()
pageControl?.numberOfPages = 11
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 11;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: ImageCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
cell.label.text = "Cell \(indexPath.row)"
cell.backgroundImageView.image = UIImage(named: "Parallax \(indexPath.row + 1)")
// Parallax cell setup
cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection)
return cell
}
@IBAction open func pageChanged(_ sender: UIPageControl) {
print(sender.currentPage)
}
// MARK: Delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return collectionView.bounds.size;
}
// MARK: Scrolling
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Parallax visible cells
for cell: ImageCollectionViewCell in collectionView.visibleCells as! [ImageCollectionViewCell] {
cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
这里是一个完整的 class,在水平集合视图中带有页面控件分页。
这正在处理我的一个应用程序,现在,并且工作正常。如果你不能让它工作,请随时问我,我会帮助你。
首先,在 Storyboard 中,您必须设置 CollectionView:
布局:流程
滚动方向:水平
启用滚动
启用分页
@IBOutlet weak var collectionView: UICollectionView! //img: 77
@IBOutlet weak var pageControl: UIPageControl!
var thisWidth:CGFloat = 0
override func awakeFromNib() {
super.awakeFromNib()
thisWidth = CGFloat(self.frame.width)
collectionView.delegate = self
collectionView.dataSource = self
pageControl.hidesForSinglePage = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
self.pageControl.currentPage = indexPath.section
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
thisWidth = CGFloat(self.frame.width)
return CGSize(width: thisWidth, height: self.frame.height)
}
我不喜欢接受的答案。有时,willDisplay cell
会 return 页面控件的错误页面,具体取决于用户交互。
我用的是:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
pageControl.currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
}
这将在用户完成滚动后更新页面,从而使 pageControl
的 currentPage
更加准确。
等待 scrollViewDidEndDecelerating
导致 UIPageControl
更新缓慢。如果您想要响应更快的 UI,我建议改为实施 scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)
.
Swift 4 个示例,其中每个集合视图部分是一个页面:
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if let collectionView = scrollView as? ScoreCollectionView,
let section = collectionView.indexPathForItem(at: targetContentOffset.pointee)?.section {
self.pageControl.currentPage = section
}
}
为了获得响应更快的 UIPageControl,我更喜欢使用 scrollViewDidScroll
并计算相对于 scrollView 水平中心的偏移量。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offSet = scrollView.contentOffset.x
let width = scrollView.frame.width
let horizontalCenter = width / 2
pageControl.currentPage = Int(offSet + horizontalCenter) / Int(width)
}
Luke's answer 对我来说是一个好的开始,但它有两个问题:它没有经常更新(已在其他答案中指出)但最重要的是它没有显示最后一项的正确页面在我的 collection 视图(水平方向)中,它仅在项目快要离开屏幕时才切换页面。
对于第一个问题,正如其他人指出的那样,使用 scrollViewDidScroll
提供了更好的体验。我担心如此频繁地调用性能问题,但没有注意到任何问题。
关于第二个问题,对于我的用例,找到位于屏幕中心的单元格的indexPath提供了更好的解决方案。请记住,如果您的用例可以在屏幕上容纳两个以上的单元格,则可能需要对此进行调整。这是因为您的最后一个单元格永远不会到达屏幕中间。我会争辩说,尽管在那种情况下使用 UIPageControl
可能并不理想。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionView.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.cvImageListing.contentOffset, size: self.cvImageListing.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.cvImageListing.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
Swift 5 工作非常顺畅
//MARK:- For Display the page number in page controll of collection view Cell
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionview.contentOffset, size: self.collectionview.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionview.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
swift 5 例:
根据CollectionView的Index设置pageController CurrentPage的函数:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionView.indexPathForItem(at: visiblePoint) {
self.pageController.currentPage = visibleIndexPath.row
}
}
在选择 PageController 时滚动 CollectionView 的 PageControllerAction 函数:
@IBAction func pageControllerAction(_ sender: UIPageControl) {
self.collectionView.scrollToItem(at: IndexPath(row: sender.currentPage, section: 0), at: .centeredHorizontally, animated: true)
}
只需添加此功能
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
//Test the offset and calculate the current page after scrolling ends
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
//Change the indicator
self.pageControl.currentPage = Int(currentPage);
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let OFFSet = scrollView.contentOffset.x
let width = scrollView.frame.width
let horizontalCenter = width / 2
pageviewControl.currentPage = Int(OFFSet + horizontalCenter) / Int(width)
}
我有 UICollectionView
个水平图像列表代码。我想在显示滚动图像时添加 PageControl
,我添加了 pagecontrol 选择器和 IBOutlet
但如何将它集成到 UICollecitonView
之间?
我的代码如下:
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@IBOutlet weak var View : DesignableView!
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var collectionViewLayout: UICollectionViewFlowLayout!
@IBOutlet open weak var pageControl: UIPageControl? {
didSet {
pageControl?.addTarget(self, action: #selector(ViewController.pageChanged(_:)), for: .valueChanged)
}
}
override func viewDidLoad() {
super.viewDidLoad()
pageControl?.numberOfPages = 11
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 11;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: ImageCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
cell.label.text = "Cell \(indexPath.row)"
cell.backgroundImageView.image = UIImage(named: "Parallax \(indexPath.row + 1)")
// Parallax cell setup
cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection)
return cell
}
@IBAction open func pageChanged(_ sender: UIPageControl) {
print(sender.currentPage)
}
// MARK: Delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return collectionView.bounds.size;
}
// MARK: Scrolling
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Parallax visible cells
for cell: ImageCollectionViewCell in collectionView.visibleCells as! [ImageCollectionViewCell] {
cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
这里是一个完整的 class,在水平集合视图中带有页面控件分页。 这正在处理我的一个应用程序,现在,并且工作正常。如果你不能让它工作,请随时问我,我会帮助你。
首先,在 Storyboard 中,您必须设置 CollectionView:
布局:流程
滚动方向:水平
启用滚动
启用分页
@IBOutlet weak var collectionView: UICollectionView! //img: 77
@IBOutlet weak var pageControl: UIPageControl!
var thisWidth:CGFloat = 0
override func awakeFromNib() {
super.awakeFromNib()
thisWidth = CGFloat(self.frame.width)
collectionView.delegate = self
collectionView.dataSource = self
pageControl.hidesForSinglePage = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
self.pageControl.currentPage = indexPath.section
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
thisWidth = CGFloat(self.frame.width)
return CGSize(width: thisWidth, height: self.frame.height)
}
我不喜欢接受的答案。有时,willDisplay cell
会 return 页面控件的错误页面,具体取决于用户交互。
我用的是:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
pageControl.currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
}
这将在用户完成滚动后更新页面,从而使 pageControl
的 currentPage
更加准确。
等待 scrollViewDidEndDecelerating
导致 UIPageControl
更新缓慢。如果您想要响应更快的 UI,我建议改为实施 scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)
.
Swift 4 个示例,其中每个集合视图部分是一个页面:
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if let collectionView = scrollView as? ScoreCollectionView,
let section = collectionView.indexPathForItem(at: targetContentOffset.pointee)?.section {
self.pageControl.currentPage = section
}
}
为了获得响应更快的 UIPageControl,我更喜欢使用 scrollViewDidScroll
并计算相对于 scrollView 水平中心的偏移量。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offSet = scrollView.contentOffset.x
let width = scrollView.frame.width
let horizontalCenter = width / 2
pageControl.currentPage = Int(offSet + horizontalCenter) / Int(width)
}
Luke's answer 对我来说是一个好的开始,但它有两个问题:它没有经常更新(已在其他答案中指出)但最重要的是它没有显示最后一项的正确页面在我的 collection 视图(水平方向)中,它仅在项目快要离开屏幕时才切换页面。
对于第一个问题,正如其他人指出的那样,使用 scrollViewDidScroll
提供了更好的体验。我担心如此频繁地调用性能问题,但没有注意到任何问题。
关于第二个问题,对于我的用例,找到位于屏幕中心的单元格的indexPath提供了更好的解决方案。请记住,如果您的用例可以在屏幕上容纳两个以上的单元格,则可能需要对此进行调整。这是因为您的最后一个单元格永远不会到达屏幕中间。我会争辩说,尽管在那种情况下使用 UIPageControl
可能并不理想。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionView.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.cvImageListing.contentOffset, size: self.cvImageListing.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.cvImageListing.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
Swift 5 工作非常顺畅
//MARK:- For Display the page number in page controll of collection view Cell
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionview.contentOffset, size: self.collectionview.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionview.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
swift 5 例:
根据CollectionView的Index设置pageController CurrentPage的函数:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionView.indexPathForItem(at: visiblePoint) {
self.pageController.currentPage = visibleIndexPath.row
}
}
在选择 PageController 时滚动 CollectionView 的 PageControllerAction 函数:
@IBAction func pageControllerAction(_ sender: UIPageControl) {
self.collectionView.scrollToItem(at: IndexPath(row: sender.currentPage, section: 0), at: .centeredHorizontally, animated: true)
}
只需添加此功能
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
//Test the offset and calculate the current page after scrolling ends
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
//Change the indicator
self.pageControl.currentPage = Int(currentPage);
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let OFFSet = scrollView.contentOffset.x
let width = scrollView.frame.width
let horizontalCenter = width / 2
pageviewControl.currentPage = Int(OFFSet + horizontalCenter) / Int(width)
}