Какой-то "глобальный" для IBDesignables?

В раскадровке есть UIView с ограничением, например, пропорциональной высотой 0.1.

Представьте, что у вас есть аналогичное ограничение "0,1", на представлениях во многих разных сценах.

Предположим, вы хотите изменить значение от 0,1 до 0,975.

Вы должны изменить его индивидуально повсюду.

Есть ли способ сделать своего рода "глобальное значение" , используя @IBInspectable и/или ограничения?

Чтобы вы могли изменить их все сразу и увидеть результаты сразу же в раскадровке.

(Конечно, во время выполнения вы могли распространять их в коде, но лучше видеть его на раскадровке.)


Обратите внимание, например, что решение Wain ниже работает отлично: вы можете установить значение один раз и повлиять повсюду в приложении. Но, к сожалению, это происходит только во время выполнения, вы не видите его на раскадровке.

Ответ 1

Я не пробовал это, и это просто набирается здесь, поэтому оправдайте опечатки, но я бы подумал о создании расширения на NSLayoutConstraint, что-то вроде строк:

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

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

а затем используя пользовательские атрибуты времени выполнения в Xcode, укажите имя для использования:

commonConstant, type String, value name

Итак, вот так, на каждом Constraint в любом месте раскадровки:

введите описание изображения здесь

Ответ 2

Я не могу придумать, как заставить IB обновлять все "экземпляры" во время разработки, когда один экземпляр имеет изменение значения свойства (И я думаю, что это обычно было бы нежелательным и нестандартным поведением). Я уверен, что это невозможно, потому что я не думаю, что IB хранит экземпляр вашего пользовательского представления в памяти на протяжении сеанса IB. Я думаю, что он создает экземпляр представления, задает на нем свойства, снимет его для рендеринга и затем освобождает его.

Должно быть возможно настроить свойства, которые устанавливают значения по умолчанию для будущих экземпляров вашего представления. Мы можем добиться этого, сохранив значения "по умолчанию" в NSUserDefaults (XCode) и прочитав значение по умолчанию внутри 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), если вы в порядке, вынудив IB перезагрузить файл xib/storyboard вообще. Для этого вам, вероятно, придется использовать вышеприведенную технику и расширить ее, чтобы включить код в пользовательский метод initWithCoder: на вашем представлении.

Возможно, вы могли бы стать очень сложными и попытаться "коснуться" xib файла, который редактируется, и это может заставить IB перезагрузить?

Ответ 3

Я попытался найти что-то подобное, когда начал работать с помощью Storyboard и Interface Builder. К сожалению, xCode не настолько масштабируема, и централизация кода с помощью Interface Builder не может быть легко реализована, как это может быть сделано в Android-разработке, например.

Вы можете попробовать что-то вроде этого, использовать пользовательский атрибут @IBDesignable в расширениях UIView и изменениях ограничений или добавить ограничение во время выполнения (но я не знаю, повлияет ли это на 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
        }
    }
}

Это может быть отправной точкой. Надеюсь, что это поможет.