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

复制UIView到另一页面时如何传递原视图的Frame?

解决复制UIView到其他页面时Frame丢失的问题

问题根源

  1. NSKeyedArchiver/NSKeyedUnarchiver 归档复制视图时,不会保留原视图动态计算后的Frame(尤其是原视图用AutoLayout约束时,Frame是布局完成后临时计算的结果,归档仅保存视图属性和约束,不存储最终Frame值)。
  2. 第二个页面的布局逻辑混乱:
    • 错误给容器视图copyView添加自引用约束,完全无效
    • 子视图添加顺序颠倒,应先将复制的viewCpy加入copyView再设置布局
    • 多余的DispatchQueue.main.async和重复调用布局方法

修复方案

1. 优化视图复制与Frame传递

不依赖归档复制时的Frame,单独将原视图的Frame值传递到目标页面:

修改第一个页面代码:

if let vc = Router.filterPopup.instance as? FilterOptionPopUpVC {
    vc.hidesBottomBarWhenPushed = true
    // 复制视图
    vc.viewCpy = self.btnSignIn?.copyView() as! UIView
    // 单独保存原视图的Frame
    vc.originViewFrame = self.btnSignIn?.frame ?? CGRect()
    
    print("原视图Frame:- \(self.btnSignIn?.frame ?? CGRect())")
    self.navigationController?.present(vc, animated: true)
}

在FilterOptionPopUpVC中添加属性:

var viewCpy: UIView!
var originViewFrame: CGRect = .zero

2. 修复第二个页面的布局逻辑

根据需求选择直接设置Frame或用AutoLayout约束:

方案A:直接设置Frame(简单快捷)
override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    
    viewCpy.translatesAutoresizingMaskIntoConstraints = true
    copyView.addSubview(viewCpy)
    // 应用原视图的Frame
    viewCpy.frame = originViewFrame
    
    print("复制后视图Frame:- \(viewCpy.frame)")
}
方案B:用AutoLayout匹配原Frame的尺寸和位置
override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    
    viewCpy.translatesAutoresizingMaskIntoConstraints = false
    copyView.addSubview(viewCpy)
    
    NSLayoutConstraint.activate([
        // 匹配原Frame的位置
        viewCpy.leadingAnchor.constraint(equalTo: copyView.leadingAnchor, constant: originViewFrame.origin.x),
        viewCpy.topAnchor.constraint(equalTo: copyView.topAnchor, constant: originViewFrame.origin.y),
        // 匹配原Frame的尺寸
        viewCpy.widthAnchor.constraint(equalToConstant: originViewFrame.size.width),
        viewCpy.heightAnchor.constraint(equalToConstant: originViewFrame.size.height)
    ])
    
    copyView.layoutIfNeeded()
    print("复制后视图Frame:- \(viewCpy.frame)")
}

3. 可选:改进视图复制方法

避免强制解包风险:

extension UIView {
    func copyView() -> UIView? {
        guard let data = try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false) else {
            return nil
        }
        return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIView
    }
}

额外注意

如果原视图Frame是相对于父视图的,且目标页面容器与原父视图尺寸不同,需转换坐标系统:

// 原页面中转换为屏幕坐标
if let windowFrame = self.btnSignIn?.superview?.convert(self.btnSignIn.frame, to: UIApplication.shared.keyWindow) {
    vc.originViewFrame = windowFrame
}

// 目标页面中转换为容器坐标
let targetFrame = self.copyView.convert(originViewFrame, from: UIApplication.shared.keyWindow)
viewCpy.frame = targetFrame

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 03:17:35