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

如何在所有屏幕尺寸下适配UIPageViewController的多页文本显示

解决UIPageViewController全屏文本分页的多设备适配问题

嘿,作为刚接触Swift/Xcode的新手,遇到这种跨设备的文本适配问题太正常了!你的核心痛点是固定文本量或固定字号无法适配不同屏幕尺寸,其实解决思路很简单:根据当前设备的屏幕可用空间,动态计算一页能容纳的文本量,再把整段文本分割成刚好填满每页的子内容。下面给你一步步拆解实现方法,都是适合新手的实操步骤:

一、核心思路:动态计算每页文本容量

我们需要一个工具方法,输入完整文本、字体样式、页面容器尺寸,输出分割好的每页文本数组。原理是利用NSString的boundingRect方法,计算文本在指定容器内的高度,从而反推一页能装下多少字符。

示例工具方法代码

import UIKit

func splitTextIntoPages(fullText: String, font: UIFont, pageSize: CGSize) -> [String] {
    var pages = [String]()
    let baseAttributes: [NSAttributedString.Key: Any] = [.font: font]
    
    var currentStartIndex = fullText.startIndex
    while currentStartIndex < fullText.endIndex {
        var currentEndIndex = fullText.endIndex
        var currentText = String(fullText[currentStartIndex..<currentEndIndex])
        var textSize = NSAttributedString(string: currentText, attributes: baseAttributes)
            .boundingRect(with: pageSize, options: [.usesLineFragmentOrigin], context: nil).size
        
        // 如果当前文本超出页面,逐步减少字符直到刚好容纳
        while textSize.height > pageSize.height && currentEndIndex > currentStartIndex {
            currentEndIndex = fullText.index(before: currentEndIndex)
            currentText = String(fullText[currentStartIndex..<currentEndIndex])
            textSize = NSAttributedString(string: currentText, attributes: baseAttributes)
                .boundingRect(with: pageSize, options: [.usesLineFragmentOrigin], context: nil).size
        }
        
        pages.append(currentText)
        currentStartIndex = currentEndIndex
    }
    
    return pages
}

二、配置分页的子ViewController

每个分页页面用一个UITextView(禁用滚动)来显示文本,确保文本刚好填满整个页面:

class PageContentViewController: UIViewController {
    var pageText: String!
    let textView = UITextView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 配置UITextView:禁用滚动,铺满整个可用页面(适配安全区)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.isScrollEnabled = false
        textView.font = UIFont.systemFont(ofSize: 17) // 可自定义字号
        textView.text = pageText
        textView.textAlignment = .justified // 可选:设置两端对齐更美观
        view.addSubview(textView)
        
        // 用AutoLayout绑定到安全区边缘
        NSLayoutConstraint.activate([
            textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            textView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            textView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
    }
}

三、在UIPageViewController中整合逻辑

在你的UIPageViewController里,先获取当前设备的页面尺寸,分割文本,再实现数据源方法:

class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    var pageTexts: [String] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dataSource = self
        
        // 1. 获取当前页面的可用尺寸(去掉安全区后的大小)
        let pageSize = view.safeAreaLayoutGuide.layoutFrame.size
        // 2. 替换成你的完整长文本
        let fullText = "这里放入你的长文本内容,比如书籍章节、文章段落等..."
        // 3. 分割文本为每页内容
        pageTexts = splitTextIntoPages(fullText: fullText, font: UIFont.systemFont(ofSize: 17), pageSize: pageSize)
        
        // 初始化显示第一页
        if let firstPageVC = createPageVC(at: 0) {
            setViewControllers([firstPageVC], direction: .forward, animated: false, completion: nil)
        }
    }
    
    // 创建对应索引的页面VC
    func createPageVC(at index: Int) -> PageContentViewController? {
        guard index >= 0 && index < pageTexts.count else { return nil }
        let vc = PageContentViewController()
        vc.pageText = pageTexts[index]
        return vc
    }
    
    // UIPageViewController数据源方法:上一页
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let currentVC = viewController as? PageContentViewController,
              let currentIndex = pageTexts.firstIndex(of: currentVC.pageText),
              currentIndex > 0 else { return nil }
        return createPageVC(at: currentIndex - 1)
    }
    
    // UIPageViewController数据源方法:下一页
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let currentVC = viewController as? PageContentViewController,
              let currentIndex = pageTexts.firstIndex(of: currentVC.pageText),
              currentIndex < pageTexts.count - 1 else { return nil }
        return createPageVC(at: currentIndex + 1)
    }
}

四、关键细节说明

  • 安全区适配:用safeAreaLayoutGuide绑定布局,避免文本被状态栏、导航栏遮挡,完美适配从iPhone4到iPhone8 Plus的所有机型。
  • 自定义样式兼容:如果需要设置行距、字体颜色等样式,只需在baseAttributes里添加对应的属性(比如.lineSpacing),计算文本高度时会自动考虑这些样式。
  • 性能优化:如果文本特别长,建议把分割逻辑放在后台线程执行,完成后再回到主线程更新UI,避免界面卡顿。

这样处理后,不管是小屏的iPhone4还是大屏的iPhone8 Plus,每一页的文本都会刚好填满整个屏幕,用户滑动切换时的体验就流畅自然啦!

内容的提问来源于stack exchange,提问作者user67478

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:13:24