Client error attempting to change layout margins of a private view

本文介绍了一种解决iOS13中UINavigationBar自动布局导致的边距问题的方法。通过调整_UINavigationBarContentView的frame,而非直接修改layoutMargins,避免了在iOS13上运行时的应用崩溃。

从 iOS 11 开始,UINavigationBar 使用了自动布局,左右两边的按钮到屏幕之间会有 16 或 20 的边距。

为了避免点击到间距的空白处没有响应,通常做法是:定义一个 UINavigationBar 子类,重写 layoutSubviews 方法,在此方法里遍历 subviews 获取 _UINavigationBarContentView,并将其 layoutMargins 设置为 UIEdgeInsetsZero

 

- (void)layoutSubviews {
    [super layoutSubviews];

    for (UIView *subview in self.subviews) {
        if ([NSStringFromClass([subview class]) containsString:@"_UINavigationBarContentView"]) {
            subview.layoutMargins = UIEdgeInsetsZero;
            break;
        }
    }
}

然而,这种做法在 iOS 13 中会导致崩溃,崩溃信息如下

Client error attempting to change layout margins of a private view

试图更改私有视图的布局边距时出现错误

解决方案:

使用设置 frame 的方式,让 _UINavigationBarContentView 向两边伸展,从而抵消两边的边距

- (void)layoutSubviews {
    [super layoutSubviews];

    for (UIView *subview in self.subviews) {
        if ([NSStringFromClass([subview class]) containsString:@"_UINavigationBarContentView"]) {
            if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
                UIEdgeInsets margins = subview.layoutMargins;
                subview.frame = CGRectMake(-margins.left, -margins.top, margins.left + margins.right + subview.frame.size.width, margins.top + margins.bottom + subview.frame.size.height);
            } else {
                subview.layoutMargins = UIEdgeInsetsZero;
            }
            break;
        }
    }
}

当在iOS保存时出现 `TypeError: Attempting to change the getter of an unconfigurable property.` 错误,通常是因为尝试修改一个不可配置(`configurable` 为 `false`)的属性的 `getter` 函数。以下是一些可能的解决办法: ### 检查属性配置 首先要确认该属性是否真的不可配置。可以通过 `Object.getOwnPropertyDescriptor` 方法来查看属性的描述符: ```javascript const obj = { someProperty: 'value' }; const descriptor = Object.getOwnPropertyDescriptor(obj, 'someProperty'); console.log(descriptor.configurable); // 检查是否为 false ``` 如果 `configurable` 是 `false`,则不能直接修改 `getter`。此时,有以下几种处理方式。 ### 创建新对象 如果可能,创建一个新的对象来替代原对象,并在新对象上定义所需的属性和 `getter`: ```javascript const originalObj = { someProperty: 'value' }; const newObj = { ...originalObj }; Object.defineProperty(newObj, 'someProperty', { get: function() { // 自定义 getter 逻辑 return 'new value'; } }); ``` ### 避免直接修改 尽量避免直接修改不可配置属性的 `getter`。可以考虑使用其他方式来实现相同的功能,例如添加新的属性或方法。 ### 检查第三方库或框架 如果使用了第三方库或框架,可能是它们在内部定义了不可配置的属性。检查这些库的文档,看是否有相关的配置选项或替代方法。 ### 动态创建属性 在创建属性时,确保 `configurable` 为 `true`,这样后续就可以修改 `getter`: ```javascript const obj = {}; Object.defineProperty(obj, 'someProperty', { value: 'value', configurable: true, // 允许后续修改 writable: true, enumerable: true }); // 后续可以修改 getter Object.defineProperty(obj, 'someProperty', { get: function() { return 'new value'; } }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值