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

iOS自定义键盘选中CollectionView项时调整SFSafariViewController高度问题

问题分析与解决方案

首先得明确核心问题:你的自定义键盘属于App Extension,它的视图层级和权限都和主App有很大区别,你之前的代码犯了两个关键错误——错误地操作键盘自身的高度约束来控制Safari窗口,以及用了不正确的方式呈现SFSafariViewController。

为什么你的代码没效果?

  1. 视图层级分离:SFSafariViewController是模态弹出的,属于宿主App的窗口层级,和键盘的视图完全独立。你修改self.heightConstraint只是在调整键盘本身的高度,和Safari窗口没有任何关系,而且键盘的高度受系统约束管控,手动修改后大概率会被系统重置。
  2. 错误的present方式:键盘的UIInputViewController不属于宿主App的视图控制器链,直接调用self.present无法让Safari控制器正确显示在宿主App的界面上。

修正后的实现方案

第一步:获取宿主App的顶层视图控制器

键盘扩展无法直接访问宿主App的视图层级,我们需要先找到宿主App的顶层VC,再通过它来present Safari控制器:

private func getTopHostViewController() -> UIViewController? {
    if #available(iOS 13.0, *) {
        // iOS13+ 用Scene获取窗口
        guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let window = scene.windows.first else { return nil }
        var topVC = window.rootViewController
        while let presentedVC = topVC?.presentedViewController {
            topVC = presentedVC
        }
        return topVC
    } else {
        // iOS13以下直接取keyWindow
        guard let window = UIApplication.shared.keyWindow else { return nil }
        var topVC = window.rootViewController
        while let presentedVC = topVC?.presentedViewController {
            topVC = presentedVC
        }
        return topVC
    }
}

第二步:修改CollectionView选中事件的代码

替换你原来的didSelectItemAt方法,改用正确的方式呈现并控制Safari窗口:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if collectionView == self.key.colImages {
        guard let articleURLString = self.articles[indexPath.item].url,
              let targetURL = URL(string: articleURLString) else { return }
        
        // 复制URL到剪贴板(保留你的原有逻辑)
        UIPasteboard.general.string = articleURLString
        
        // 创建并配置Safari控制器
        let safariVC = SFSafariViewController(url: targetURL, entersReaderIfAvailable: true)
        safariVC.delegate = self
        
        // 配置Safari的外观(保留你的原有逻辑)
        if #available(iOS 10.0, *) {
            safariVC.preferredBarTintColor = .white
            safariVC.preferredControlTintColor = UIColor(red:0.19, green:0.58, blue:0.91, alpha:1.0)
        } else {
            safariVC.view.tintColor = .white
        }
        
        // 设置Safari的模态样式(iOS13+支持非全屏弹窗)
        if #available(iOS 13.0, *) {
            safariVC.modalPresentationStyle = .pageSheet
            // 自定义弹窗高度(这里设置为500,你可以根据需求调整)
            safariVC.preferredContentSize = CGSize(width: UIScreen.main.bounds.width, height: 500)
        }
        
        // 通过宿主App的顶层VC来present
        if let topHostVC = getTopHostViewController() {
            topHostVC.present(safariVC, animated: true, completion: nil)
        }
    } else {
        self.fetchArticles(fromSource: "\(categoriesArray[indexPath.row])")
    }
}

额外注意事项

  • 开启键盘的开放权限:在你的键盘Extension的Info.plist中,确保RequestsOpenAccess设置为YES,否则无法访问UIApplication.shared以及执行跨App的视图呈现操作。
  • 系统约束兼容:键盘自身的高度尽量交给系统管理,不要手动修改它的约束,否则可能导致键盘布局异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:51:40