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

为何无法移除UIView扩展中添加的防截屏安全UITextField?

问题根源分析

你遇到的核心问题是手动篡改了视图的Layer层级,导致UITextField的视图与它的Layer分离,破坏了UIKit的视图-Layer对应关系:

  • 你先把secureTextField作为子视图插入当前View,但紧接着用layer.superlayer?.addSublayer(secureTextField.layer)把它的Layer移到了当前View的父Layer上,直接让TextField的视图和Layer脱节。
  • 后续secureTextField.layer.sublayers?.last?.addSublayer(layer)又把当前View的Layer挂到TextField的Layer子层里,彻底打乱了正常的视图层级,viewWithTag自然找不到这个“半游离”的TextField。
修复方案

移除所有手动操作Layer的代码,仅通过约束让secureTextField覆盖当前View即可——UIKit会自动处理Layer的层级关系,不需要你手动调整。

修改后的代码:

extension UIView {

    private struct Constants {
        static var secureTextFieldTag: Int { 54321 }
    }

    func setScreenCaptureProtection() {
        // 检查当前视图下是否已有保护控件,避免重复添加
        if viewWithTag(Constants.secureTextFieldTag) is UITextField {
            return
        }
        
        guard superview != nil else {
            // 当前视图还未加入父视图,递归处理子视图
            for subview in subviews {
                subview.setScreenCaptureProtection()
            }
            return
        }
        
        let secureTextField = UITextField()
        secureTextField.backgroundColor = .clear
        secureTextField.translatesAutoresizingMaskIntoConstraints = false
        secureTextField.tag = Constants.secureTextFieldTag
        secureTextField.isSecureTextEntry = true
        secureTextField.isUserInteractionEnabled = false
        // 插入到最底层,避免遮挡当前视图内容
        insertSubview(secureTextField, at: 0)
        
        // 批量激活约束,让TextField完全覆盖当前视图
        NSLayoutConstraint.activate([
            secureTextField.topAnchor.constraint(equalTo: topAnchor),
            secureTextField.bottomAnchor.constraint(equalTo: bottomAnchor),
            secureTextField.leadingAnchor.constraint(equalTo: leadingAnchor),
            secureTextField.trailingAnchor.constraint(equalTo: trailingAnchor)
        ])
    }

    func removeScreenCaptureProtection() {
        if let secureTextField = viewWithTag(Constants.secureTextFieldTag) as? UITextField {
            secureTextField.removeFromSuperview()
        } else {
            for subview in subviews {
                subview.removeScreenCaptureProtection()
            }
        }
    }
}
关键修改点
  1. 删除了layer.superlayer?.addSublayer(secureTextField.layer)和secureTextField.layer.sublayers?.last?.addSublayer(layer)这两行破坏层级的代码。
  2. 将约束改为用NSLayoutConstraint.activate批量激活,代码更简洁规范。
  3. 保留insertSubview(secureTextField, at: 0)确保保护控件在最底层,不会遮挡原视图内容。

修改后,secureTextField会作为当前View的正常子视图存在,viewWithTag就能准确找到它并完成移除操作。

内容的提问来源于stack exchange,提问作者Xavier Duvan Melo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:15:08