7

在情节提要中有一个 UIView,具有例如“0.1”比例高度的约束。

想象一下,在许多不同场景中的视图上,您​​有一个类似的约束“0.1”。

假设您要将值 0.1 更改为 0.975。

您必须在任何地方单独更改它。

有没有办法使用@IBInspectable 和/或约束来制作一种“全局价值” ?

这样您就可以一次全部更改它们,并在情节提要中一次看到所有结果。

(当然,在运行时你可以在代码中传播这些。但最好在故事板上看到它。)


例如,请注意以下 Wain 的解决方案完美运行:您可以设置一次值,并影响应用程序中的所有位置。但不幸的是,它只在运行时这样做,您在情节提要上看不到它。

4

3 回答 3

4

我没有尝试过,这只是在这里输入的,所以请原谅拼写错误,但我会考虑在 上创建一个扩展NSLayoutConstraint,类似于:

let constants = [
    "bannerHeight" : CGFloat(50)
]

extension NSLayoutConstraint {
func setCommonConstant(name: String) {
    self.constant = constants[name]!
}
}

然后在 Xcode 中使用用户定义的运行时属性,因此指定要使用的名称:

commonConstant, type String, value name

所以,像这样,在情节提要的任何地方的每个约束上:

在此处输入图像描述

于 2016-06-23T19:42:48.620 回答
3

当单个实例具有属性值更改时,我想不出一种方法让 IB 在设计时更新所有“实例”(而且我认为这通常是不希望的和非标准行为)。我相当肯定它不能完成,因为我认为 IB 在 IB 会话期间不会将您的自定义视图的实例保留在内存中。我认为它的作用是实例化视图,在其上设置属性,对其进行快照以进行渲染,然后释放它。

应该可以设置属性来设置视图的未来实例使用的“默认”值。我们可以通过将“默认”值存储在NSUserDefaults(XCode's)中并读取其中的默认值来实现这一点initWithFrame:,IB 将调用该默认值来初始化一个新实例。我们可以使用#if 对所有这些默认内容进行门控TARGET_INTERFACE_BUILDER,这样它就不会在运行时出现在设备上。

IB_DESIGNABLE
@interface CoolView : UIView

@property (strong, nonatomic) IBInspectable UIColor* frameColor;

#if TARGET_INTERFACE_BUILDER
@property (strong, nonatomic) IBInspectable UIColor* defaultFrameColor;
#endif

@end

@implementation CoolView

- (id) initWithFrame:(CGRect)frame
{
    self = [super initWithFrame: frame];
    if ( self != nil ) {

#if TARGET_INTERFACE_BUILDER
        NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey: @"defaultCoolViewFrameColor"];
        if ( colorData != nil ) {
            self.frameColor = [NSKeyedUnarchiver unarchiveObjectWithData: colorData];;
        }
#endif

    }
    return self;
}

- (void) drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 10);
    CGRect f = CGRectInset(self.bounds, 10, 10);
    [self.frameColor set];
    UIRectFrame(f);
}

#if TARGET_INTERFACE_BUILDER
- (void) setDefaultFrameColor:(UIColor *)defaultFrameColor
{
    _defaultFrameColor = defaultFrameColor;

    NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject: defaultFrameColor];
    [[NSUserDefaults standardUserDefaults] setObject:colorData forKey:@"defaultCoolViewFrameColor"];
}
#endif

@end

如果您同意强制 IB 完全重新加载您的 xib/storyboard 文件,您可能会更接近您的原始目标(更新 IB 中的所有“实例”)。为此,您可能必须使用上述技术并将其扩展为initWithCoder:在您的视图上的自定义方法中包含代码。

您可能会变得非常棘手并尝试“触摸”正在编辑的 xib 文件,这可能会提示 IB 重新加载?

于 2016-07-05T23:51:11.620 回答
2

当我开始使用 Storyboard 和 Interface Builder 进行开发时,我试图找到类似的东西。不幸的是,xCode 的可扩展性不高,使用 Interface Builder 的代码集中化不能像在 Android 开发中那样轻松实现。

您可以尝试这样的事情,在 UIView 扩展中使用自定义 @IBDesignable 属性并更改约束值或在运行时添加约束(但我不知道它是否也会影响 Interface Builder):

extension UIView {
    @IBInspectable var insertTopConstraint: Bool {
        set {
            // suppose 10 is your fixed value
            addConstraint(NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 10))
            updateConstraintsIfNeeded() // could be useful..
        }
        get {
            return true
        }
    }
}

这可能是一个起点。希望能帮助到你

于 2016-06-23T19:50:24.833 回答