如何配置Scroll View?解决引导页启动直接跳转至最后页问题
问题:ScrollView引导页启动直接跳转到最后一页
我正在开发一款应用,用Scroll View实现7页引导页功能,预期滚动或点击按钮可切换到下一页,但程序启动后直接跳转到最后一页。
代码实现
// // WelcomeViewController.swift // Student Central v2 // // Created by Varshith Peddi on 2/21/23. // import UIKit class WelcomeViewController: UIViewController { @IBOutlet var holderView: UIView! @IBOutlet var scrollView: UIScrollView! @IBOutlet var imageView: UIImageView! @IBOutlet var label: UILabel! @IBOutlet var description1: UILabel! @IBOutlet var button: UIButton! @IBOutlet var skipButton: UIButton! /* private let pageControl: UIPageControl = { let pageControl = UIPageControl() pageControl.numberOfPages = 7 pageControl.pageIndicatorTintColor = UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0) pageControl.currentPageIndicatorTintColor = .black return pageControl }() */ override func viewDidLoad() { super.viewDidLoad() scrollView.delegate = self //pageControl.addTarget(self, action: #selector(pageControlDidChange(_:)), for: .valueChanged) //view.addSubview(pageControl) // Do any additional setup after loading the view. configure() } /* @objc private func pageControlDidChange(_ sender: UIPageControl){ let current = sender.currentPage scrollView.setContentOffset(CGPoint(x: CGFloat(current) * view.frame.size.width, y: 0), animated: true) } */ override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() //pageControl.frame = CGRect(x: 10, y: 720, width: view.frame.size.width-20, height: 70) } private func configure() { // set up scrollview let titles = ["Welcome", "Maps", "Schedule", "Contact", "Quick Links", "Student Help", "Calendar"] let taglines = ["CHS Student Central will be a centralized app for all students. The\n app contains almost everything someone could wish for as a student at \nCoppell High School.", "Access both the map layout of the school inside and the map layout\n of things outside the school such as the football field, parking lot, and\n much more.", "View both your class schedule and shuttle schedule (if applicable).", "Use this section as an easy way to contact your teachers, counselors, \nand admins of Coppell High School", "This section of the app has all the frequently visited sites that students tend\n to use. It is a quick and easy way to access websites such as HAC, Clever,\n KCBY, Sidekick, and many more", "Use this section of the app if you or another student is in distress. You can\n request basic humanitarian aid such as food, shelter, or medical help. You \ncan also request services such as family support, and a lot of counseling.", "Use this to view the daily Coppell High School Calendar."] for x in 0..<7 { label.textAlignment = .center label.font = UIFont(name: "Helvetica-Bold", size: 36) label.text = titles[x] description1.textAlignment = .center description1.font = UIFont(name: "Helvetica", size: 28) description1.text = taglines[x] description1.numberOfLines = 3 imageView.contentMode = .scaleAspectFit if (x == 0){ imageView.image = UIImage(named: "Onboarding_1") } else if (x == 1){ imageView.image = UIImage(systemName: "map.fill") let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config } else if (x == 2){ imageView.image = UIImage(systemName: "list.bullet.rectangle.portrait.fill") let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config } else if (x == 3){ imageView.image = UIImage(systemName: "person.fill") let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config } else if (x == 4){ imageView.image = UIImage(systemName: "safari.fill") let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config } else if (x == 5){ imageView.image = UIImage(systemName: "cross.circle.fill") let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config } else if (x == 6){ imageView.image = UIImage(systemName: "calendar") let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config } button.setTitleColor(.white, for: .normal) button.backgroundColor = .black button.setTitle("Next", for: .normal) if (x == 6){ button.setTitle("Get Started", for: .normal) } button.layer.cornerRadius = 10 button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside) button.tag = x + 1 skipButton.setTitleColor(.systemBlue, for: .normal) skipButton.setTitle("Skip", for: .normal) skipButton.titleLabel?.font = UIFont(name: "Helvetica", size: 30) skipButton.layer.cornerRadius = 10 skipButton.addTarget(self, action: #selector(didTapButton2(_:)), for: .touchUpInside) } scrollView.isPagingEnabled = true } @objc func didTapButton(_ button:UIButton) { guard button.tag < 7 else{ //dismiss //Core.shared.setIsNotNewUser() dismiss(animated: true, completion: nil) return } //scroll to next page scrollView.setContentOffset(CGPoint(x: holderView.frame.size.width * CGFloat(button.tag), y: 0), animated: true) } @objc func didTapButton2(_ button:UIButton) { //dismiss //Core.shared.setIsNotNewUser() dismiss(animated: true, completion: nil) return } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destination. // Pass the selected object to the new view controller. } */ } extension WelcomeViewController: UIScrollViewDelegate{ func scrollViewDidScroll(_ scrollView: UIScrollView) { //pageControl.currentPage = Int(floorf(Float(scrollView.contentOffset.x) / Float(scrollView.frame.size.width))) } }
Storyboard布局

问题原因
核心错误在于configure()方法的循环逻辑:你反复修改同一组label、description1、imageView和button的属性,循环执行7次后,这些控件最终会被设置为第7页(x=6)的内容。更关键的是,你没有给ScrollView添加7个独立的页面视图,只是复用同一组控件修改内容,完全不符合分页的实现逻辑。
修复方案
1. 重构ScrollView页面结构
为每个引导页创建独立的容器视图,将页面控件放入对应容器,再添加到ScrollView并设置正确的contentSize。
2. 修改后的核心代码
private func configure() { scrollView.isPagingEnabled = true let titles = ["Welcome", "Maps", "Schedule", "Contact", "Quick Links", "Student Help", "Calendar"] let taglines = ["CHS Student Central will be a centralized app for all students. The app contains almost everything someone could wish for as a student at Coppell High School.", "Access both the map layout of the school inside and the map layout of things outside the school such as the football field, parking lot, and much more.", "View both your class schedule and shuttle schedule (if applicable).", "Use this section as an easy way to contact your teachers, counselors, and admins of Coppell High School", "This section of the app has all the frequently visited sites that students tend to use. It is a quick and easy way to access websites such as HAC, Clever, KCBY, Sidekick, and many more", "Use this section of the app if you or another student is in distress. You can request basic humanitarian aid such as food, shelter, or medical help. You can also request services such as family support, and a lot of counseling.", "Use this to view the daily Coppell High School Calendar."] let pageWidth = view.frame.width let pageHeight = scrollView.frame.height // 遍历创建7个独立页面 for x in 0..<7 { // 创建页面容器 let pageView = UIView(frame: CGRect(x: CGFloat(x) * pageWidth, y: 0, width: pageWidth, height: pageHeight)) // 创建标题Label let titleLabel = UILabel() titleLabel.textAlignment = .center titleLabel.font = UIFont(name: "Helvetica-Bold", size: 36) titleLabel.text = titles[x] titleLabel.translatesAutoresizingMaskIntoConstraints = false pageView.addSubview(titleLabel) // 创建描述Label let descLabel = UILabel() descLabel.textAlignment = .center descLabel.font = UIFont(name: "Helvetica", size: 28) descLabel.text = taglines[x] descLabel.numberOfLines = 0 descLabel.translatesAutoresizingMaskIntoConstraints = false pageView.addSubview(descLabel) // 创建ImageView let imageView = UIImageView() imageView.contentMode = .scaleAspectFit imageView.translatesAutoresizingMaskIntoConstraints = false pageView.addSubview(imageView) // 设置页面图片 if x == 0 { imageView.image = UIImage(named: "Onboarding_1") } else { let systemImageNames = ["map.fill", "list.bullet.rectangle.portrait.fill", "person.fill", "safari.fill", "cross.circle.fill", "calendar"] let image = UIImage(systemName: systemImageNames[x-1]) let config = UIImage.SymbolConfiguration(paletteColors: [UIColor(red: 176/255.0, green: 3/255.0, blue: 0/255.0, alpha: 1.0)]) imageView.preferredSymbolConfiguration = config imageView.image = image } // 创建操作按钮 let actionButton = UIButton(type: .system) actionButton.setTitleColor(.white, for: .normal) actionButton.backgroundColor = .black actionButton.setTitle(x == 6 ? "Get Started" : "Next", for: .normal) actionButton.layer.cornerRadius = 10 actionButton.tag = x actionButton.addTarget(self, action: #selector(didTapActionButton(_:)), for: .touchUpInside) actionButton.translatesAutoresizingMaskIntoConstraints = false pageView.addSubview(actionButton) // 添加页面控件约束(可根据需求调整) NSLayoutConstraint.activate([ imageView.centerXAnchor.constraint(equalTo: pageView.centerXAnchor), imageView.topAnchor.constraint(equalTo: pageView.topAnchor, constant: 100), imageView.widthAnchor.constraint(equalToConstant: 200), imageView.heightAnchor.constraint(equalToConstant: 200), titleLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 40), titleLabel.leadingAnchor.constraint(equalTo: pageView.leadingAnchor, constant: 20), titleLabel.trailingAnchor.constraint(equalTo: pageView.trailingAnchor, constant: -20), descLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20), descLabel.leadingAnchor.constraint(equalTo: pageView.leadingAnchor, constant: 20), descLabel.trailingAnchor.constraint(equalTo: pageView.trailingAnchor, constant: -20), actionButton.bottomAnchor.constraint(equalTo: pageView.bottomAnchor, constant: -80), actionButton.leadingAnchor.constraint(equalTo: pageView.leadingAnchor, constant: 40), actionButton.trailingAnchor.constraint(equalTo: pageView.trailingAnchor, constant: -40), actionButton.heightAnchor.constraint(equalToConstant: 60) ]) // 将页面添加到ScrollView scrollView.addSubview(pageView) } // 设置ScrollView内容尺寸 scrollView.contentSize = CGSize(width: CGFloat(titles.count) * pageWidth, height: pageHeight) // 配置Skip按钮 skipButton.setTitleColor(.systemBlue, for: .normal) skipButton.setTitle("Skip", for: .normal) skipButton.titleLabel?.font = UIFont(name: "Helvetica", size: 30) skipButton.layer.cornerRadius = 10 skipButton.addTarget(self, action: #selector(didTapButton2(_:)), for: .touchUpInside) } @objc func didTapActionButton(_ button: UIButton) { let currentPage = button.tag if currentPage == 6 { // 最后一页关闭引导页 dismiss(animated: true) return } // 滚动到下一页 let nextPageOffset = CGFloat(currentPage + 1) * view.frame.width scrollView.setContentOffset(CGPoint(x: nextPageOffset, y: 0), animated: true) }
3. Storyboard调整
- 移除原有的
label、description1、imageView、button控件 - 确保
scrollView约束填满父视图 - 保留
skipButton并设置固定位置约束(如右上角)
修改后,ScrollView会包含7个独立页面,启动默认显示第一页,支持滚动和按钮切换,最后一页可关闭引导页。
内容的提问来源于stack exchange,提问作者Varshith Peddi
相关产品推荐
相关产品推荐

