如何在Swift中通过代码创建带Page Controller的水平UIScrollView(无Storyboard)
Hey there! Let's walk through building a fully code-based horizontal scroll view paired with a page control—no Storyboards required. I'll break this down step by step so it's easy to follow and adapt to your project.
Step 1: Set Up Your View Controller
First, we'll start with a view controller initialized entirely via code (no nibs or Storyboards). We'll also declare our core UI components upfront:
import UIKit class PageScrollViewController: UIViewController { // Core UI elements private let scrollView = UIScrollView() private let pageControl = UIPageControl() private let contentView = UIView() // Define how many pages you want to display private let pageCount = 3 override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) setupInitialConfig() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupInitialConfig() { view.backgroundColor = .systemBackground } }
Step 2: Add and Configure UI Components
Next, we'll add our components to the main view and set up Auto Layout constraints. The contentView acts as a container for all our pages—this makes managing page layout way simpler than adding pages directly to the scroll view.
Add this method and call it in viewDidLoad:
override func viewDidLoad() { super.viewDidLoad() setupUI() } private func setupUI() { // Configure Scroll View scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.isPagingEnabled = true // Enables snap-to-page behavior scrollView.showsHorizontalScrollIndicator = false scrollView.delegate = self view.addSubview(scrollView) // Configure Content View (holds all pages) contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView) // Configure Page Control pageControl.translatesAutoresizingMaskIntoConstraints = false pageControl.numberOfPages = pageCount pageControl.currentPage = 0 pageControl.addTarget(self, action: #selector(pageControlTapped(_:)), for: .valueChanged) view.addSubview(pageControl) // Set up all constraints NSLayoutConstraint.activate([ // Scroll View constraints scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: pageControl.topAnchor, constant: -20), // Content View constraints (width = scroll view width * number of pages) contentView.topAnchor.constraint(equalTo: scrollView.topAnchor), contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor), contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: CGFloat(pageCount)), // Page Control constraints pageControl.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20), pageControl.centerXAnchor.constraint(equalTo: view.centerXAnchor), pageControl.heightAnchor.constraint(equalToConstant: 30) ]) // Add individual pages to the content view setupPages() }
Step 3: Create and Add Pages to Content View
Now let's build the actual pages. For this example, I'll make simple colored views with labels, but you can swap these out for any custom view you need:
private func setupPages() { let pageColors: [UIColor] = [.systemBlue, .systemGreen, .systemOrange] for index in 0..<pageCount { let pageView = UIView() pageView.translatesAutoresizingMaskIntoConstraints = false pageView.backgroundColor = pageColors[index] contentView.addSubview(pageView) // Add a label to each page let pageLabel = UILabel() pageLabel.translatesAutoresizingMaskIntoConstraints = false pageLabel.text = "Page \(index + 1)" pageLabel.font = .systemFont(ofSize: 24, weight: .bold) pageLabel.textColor = .white pageView.addSubview(pageLabel) // Page constraints (each page takes full width of scroll view) NSLayoutConstraint.activate([ pageView.topAnchor.constraint(equalTo: contentView.topAnchor), pageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), pageView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), pageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: CGFloat(index) * view.frame.width) ]) // Label constraints (centered on the page) NSLayoutConstraint.activate([ pageLabel.centerXAnchor.constraint(equalTo: pageView.centerXAnchor), pageLabel.centerYAnchor.constraint(equalTo: pageView.centerYAnchor) ]) } }
Step 4: Sync Scroll View and Page Control
We need two key behaviors: updating the page control when the user scrolls, and scrolling to the selected page when the user taps the page control. Add these extensions to your view controller:
extension PageScrollViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // Calculate current page based on scroll offset let currentPage = scrollView.contentOffset.x / scrollView.frame.width pageControl.currentPage = Int(round(currentPage)) } } extension PageScrollViewController { @objc private func pageControlTapped(_ sender: UIPageControl) { // Scroll to the selected page with smooth animation let targetOffset = CGFloat(sender.currentPage) * scrollView.frame.width scrollView.setContentOffset(CGPoint(x: targetOffset, y: 0), animated: true) } }
Key Tips to Keep in Mind
isPagingEnabled: This property makes the scroll view snap to each page automatically—critical for the page-based experience.- Content View Width: Setting the content view's width to
scrollView.width * pageCountensures the scroll view has enough horizontal space to display all pages. - Scroll Delegate: Using
scrollViewDidScrollkeeps the page control in perfect sync with the user's scrolling. - Smooth Transitions: The
setContentOffset(_:animated:)method gives a polished feel when tapping the page control.
How to Use This Controller
Since we're not using Storyboards, set this controller as your root view controller in SceneDelegate (iOS 13+):
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = PageScrollViewController() self.window = window window.makeKeyAndVisible() } }
That's it! You now have a fully functional horizontal scroll view with page control, built entirely in Swift without any Storyboards.
内容的提问来源于stack exchange,提问作者Sanjana Nanjappa

