问题描述
我想在iOS应用(iOS 13,swift 5.2,xcode 11.5)的欢迎屏幕上实现分页。
为此,我使用UICollectionView和UIPageControl。现在,我需要将pageControl绑定到“收藏夹”视图。
起初,我尝试使用uiscrollviewdelegate,但很快发现它不适用于合成布局。 然后,我发现了可用于合成布局部分的visibleItemsInvalidationHandler。 我尝试了类似的其他选择:
section.visibleItemsInvalidationHandler = { (visibleItems,point,env) -> Void in
self.pageControl.currentPage = visibleItems.last?.indexPath.row ?? 0
}
并这样:
section.visibleItemsInvalidationHandler = { items,contentOffset,environment in
let currentPage = Int(max(0,round(contentOffset.x / environment.container.contentSize.width)))
self.pageControl.currentPage = currentPage
}
但没有任何效果...
似乎该回调根本没有触发。如果我在其中放置打印语句,则该语句不会执行。
请在下面找到整个代码:
import Foundation
import UIKit
class WelcomeVC: UIViewController,UICollectionViewDelegate {
//MARK: - PROPERTIES
var cardsDataSource: UICollectionViewDiffableDataSource<Int,WalkthroughCard>! = nil
var cardsSnapshot = NSDiffableDataSourceSnapshot<Int,WalkthroughCard>()
var cards: [WalkthroughCard]!
var currentPage = 0
//MARK: - OUTLETS
@IBOutlet weak var signInButton: PrimaryButton!
@IBOutlet weak var walkthroughCollectionView: UICollectionView!
@IBOutlet weak var pageControl: UIPageControl!
//MARK: - VIEW DID LOAD
override func viewDidLoad() {
super.viewDidLoad()
walkthroughCollectionView.isScrollEnabled = true
walkthroughCollectionView.delegate = self
setupCards()
pageControl.numberOfPages = cards.count
configureCardsDataSource()
configureCardsLayout()
}
//MARK: - SETUP CARDS
func setupCards() {
cards = [
WalkthroughCard(title: "Welcome to abc",image: "Hello",description: "abc is an assistant to your xyz account at asdf"),WalkthroughCard(title: "Have all asdf projects at your fingertips",image: "Graphs",description: "Enjoy all project related data whithin a few taps. Even offline")
]
}
//MARK: - COLLECTION VIEW DIFFABLE DATA SOURCE
private func configureCardsDataSource() {
cardsDataSource = UICollectionViewDiffableDataSource<Int,WalkthroughCard>(collectionView: walkthroughCollectionView) {
(collectionView: UICollectionView,indexPath: IndexPath,card: WalkthroughCard) -> UICollectionViewCell? in
// Create cell
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: "WalkthroughCollectionViewCell",for: indexPath) as? WalkthroughCollectionViewCell else { fatalError("Cannot create new cell") }
//cell.layer.cornerRadius = 15
cell.walkthroughImage.image = UIImage(named: card.image)
cell.walkthroughTitle.text = card.title
cell.walkthroughDescription.text = card.description
return cell
}
setupCardsSnapshot()
}
private func setupCardsSnapshot() {
cardsSnapshot = NSDiffableDataSourceSnapshot<Int,WalkthroughCard>()
cardsSnapshot.appendSections([0])
cardsSnapshot.appendItems(cards)
cardsDataSource.apply(self.cardsSnapshot,animatingDifferences: true)
}
//MARK: - CONfigURE COLLECTION VIEW LAYOUT
func configureCardsLayout() {
walkthroughCollectionView.collectionViewLayout = generateCardsLayout()
}
func generateCardsLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),heightDimension: .fractionalHeight(1.0))
let fullPhotoItem = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),heightDimension: .fractionalHeight(1.0))
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: groupSize,subitem: fullPhotoItem,count: 1
)
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPagingCentered
let layout = UICollectionViewCompositionalLayout(section: section)
//setup pageControl
section.visibleItemsInvalidationHandler = { (items,offset,env) -> Void in
self.pageControl.currentPage = items.last?.indexPath.row ?? 0
}
return layout
}
}
解决方法
我认为您应该给UIPageViewController一个机会。我将附加其实现,以便您可以轻松地与代码集成。
您可以在单独的UIViewController中设计滑块项,并在UIPageViewController的主视图中使用所需的任何区域。
干杯!
import UIKit
import SnapKit
class WelcomeViewController: BaseViewController<WelcomeViewModel> {
@IBOutlet weak var pageControl: UIPageControl!
@IBOutlet weak var viewForPageController: UIView!
private var pageViewController: UIPageViewController!
private var introductionSliderViewControllers: [UIViewController] = []
override func viewDidLoad() {
super.viewDidLoad()
viewModel.welcomeSlidersLoaded = { [weak self] sliders in
self?.loadSliders(sliders: sliders)
}
}
private func loadSliders(sliders: [IntroductionSliderViewModel]) {
guard sliders.count > 0 else { return }
self.introductionSliderViewControllers = sliders.map{
IntroductionSliderViewController(viewModel: $0)
}
self.initializePageViewController()
}
private func initializePageViewController(){
self.pageViewController = UIPageViewController(transitionStyle: .scroll,navigationOrientation: .horizontal,options: nil)
self.viewForPageController.addSubview(self.pageViewController.view)
self.addChild(pageViewController)
self.pageViewController.view.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
self.pageViewController.delegate = self
self.pageViewController.dataSource = self
self.pageViewController.setViewControllers([introductionSliderViewControllers[0]],direction: .forward,animated: false,completion: nil)
self.pageControl.numberOfPages = introductionSliderViewControllers.count
self.pageControl.currentPage = 0
}
}
extension WelcomeViewController: UIPageViewControllerDataSource{
func pageViewController(_ pageViewController: UIPageViewController,viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let index = self.introductionSliderViewControllers.firstIndex(of: viewController),index > 0 else{return nil}
return self.introductionSliderViewControllers[index - 1]
}
func pageViewController(_ pageViewController: UIPageViewController,viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let index = self.introductionSliderViewControllers.firstIndex(of: viewController),index < self.introductionSliderViewControllers.count - 1 else{return nil}
return self.introductionSliderViewControllers[index + 1]
}
func pageViewController(_ pageViewController: UIPageViewController,didFinishAnimating finished: Bool,previousViewControllers: [UIViewController],transitionCompleted completed: Bool) {
if let vc = pageViewController.viewControllers?.first,let index = self.introductionSliderViewControllers.firstIndex(of: vc){
pageControl.currentPage = index
}
}
}
,
如果在将部分传递给布局之前为该部分设置失效处理程序,它应该可以工作:
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPagingCentered
section.visibleItemsInvalidationHandler = { (items,offset,env) -> Void in
self.pageControl.currentPage = items.last?.indexPath.row ?? 0
}
return UICollectionViewCompositionalLayout(section: section)