You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置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布局

引导页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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:04:54