2014-10-30 3 views
0

У меня есть пользовательский вид, который я создал, который должен отображаться в нескольких диспетчерах просмотра в приложении.Использование пользовательского вида в IB

Итак ... Я создал подвид UIView с xib, h и m файлами для него (и установил представление в файле xib с помощью класса), добавил мои пользовательские интерфейсы в файл xib и связал их в IBOutlets:

enter image description here

enter image description here

enter image description here

Тогда ... Я добавил 2 UIViews к View Controller, установите их класс для MYCustomView и связанных IBOutlets из тха т типа к ВК:

enter image description here

enter image description here

enter image description here

И ... это не работает ...

Теперь ... Я знаком с метод загрузки xib с использованием NSBundle loadNibNamed: owner: options: method.

Но ... Мне бы очень хотелось установить экземпляры MYCustomView в IB напрямую (ограничения, размеры и т. Д.).

Есть ли другой способ сделать это? Или я должен просто создать UIViews 'placeholder' и добавить мои экземпляры MYCustomView в качестве своих подзаголовков?

ответ

1

Нет, вы спрашиваете о ссылках на наконечники из других перьев. Есть способы добиться этого с помощью каких-то awakeAfterUsingCoder: хаков или что-то в этом роде. Обычно вы проверяете, нет ли в представлении без подвидных объектов и вида загрузки из nib, или создайте некоторый класс IB-dummy, который заменит себя целевым классом после его загрузки. Все эти методы имеют проблемы, поэтому я рекомендовал бы против них.

So Я бы предложил загрузить его из кода.

Что-то действительно круто, появилось сравнительно недавно: IBDesignable and IBInspectable, оно должно было появиться в какой-то момент.

Одним из примеров может быть какой-то временный код, который я использовал в то время как требуется структура еще не была готова (Это подкласса UIButton фиктивная IB):

// 
// That's just an example, do not use it in production code 
// 
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder 
{ 
    UIButton *buttonMain = // create button, which will replace button of dummy class from nib 
    buttonMain.translatesAutoresizingMaskIntoConstraints = NO; 

    // copy internal constraints 
    [self copyInternalConstraintsToView:buttonMain]; 

    // set titles 
    NSString *title = [self titleForState:UIControlStateNormal]; 
    [buttonMain setTitle:title forState:UIControlStateNormal]; 

    title = [self titleForState:UIControlStateHighlighted]; 
    [buttonMain setTitle:title forState:UIControlStateHighlighted]; 

    title = [self titleForState:UIControlStateDisabled]; 
    [buttonMain setTitle:title forState:UIControlStateDisabled]; 

    title = [self titleForState:UIControlStateSelected]; 
    [buttonMain setTitle:title forState:UIControlStateSelected]; 

    return buttonMain; 
} 

/** 
* Used only in awakeAfterUsingCoder, as self has only internal constraints at that moment. 
* If you'll try to use it somewhere else, behavior is undefined. 
* 
* This method is straightforward and could not suit everybody's needs. 
* 
* %Comments edited% 
* 
* @param replacementView view to add constraints to 
*/ 
- (void)copyInternalConstraintsToView:(UIView *)replacementView 
{ 
    for (NSLayoutConstraint* constraint in self.constraints) 
    { 
     if([constraint isMemberOfClass:[NSLayoutConstraint class]]) 
     { 
      id first = constraint.firstItem; 
      id second = constraint.secondItem; 
      id newFirst = first; 
      id newSecond = second; 

      BOOL match = NO; 
      if (first == self) 
      { 
       newFirst = replacementView; 
       match = YES; 
      } 
      if (second == self) 
      { 
       newSecond = replacementView; 
       match = YES; 
      } 


      // constraints to subviews from recource are not supported 
      if(newFirst != nil && newFirst != replacementView) 
      { 
       match = NO; 
      } 

      if(newSecond != nil && newSecond != replacementView) 
      { 
       match = NO; 
      } 

      if (match) 
      { 
       @try 
       { 
        NSLayoutConstraint* newConstraint = nil; 
        newConstraint = [NSLayoutConstraint constraintWithItem:newFirst 
                   attribute:constraint.firstAttribute 
                   relatedBy:constraint.relation 
                    toItem:newSecond 
                   attribute:constraint.secondAttribute 
                   multiplier:constraint.multiplier 
                    constant:constraint.constant]; 
        newConstraint.shouldBeArchived = constraint.shouldBeArchived; 
        newConstraint.priority = constraint.priority; 

        [replacementView addConstraint:newConstraint]; 
       } 
       @catch (NSException *exception) 
       { 
        NSLog(@"Constraint exception: %@\nFor constraint: %@", exception, constraint); 
       } 
      } 
     } 
    } 
} 

Некоторые ссылки: Embedding custom-view Nibs in another Nib: Towards the holy grail, An Update on Nested Nib Loading

1

Ну, я думаю, существует два возможных подхода к этому:

  1. Как вы упомянули, используйте технику с помощью loadNibNamed:owner:options
  2. Если вы используете раскадровки, вы можете использовать так называемые виды контейнеров. Просто создайте свой пользовательский вид в раскадровке, соедините его, используя segue, и вы почти закончите.

Для второго подхода вам необходимо использовать контроллер вида для ввода пользовательского вида, но это не должно быть проблемой вообще. По-моему, еще лучше использовать отдельный контроллер представлений, чтобы вставить логику контроллера вида.

2

Существует некоторая категория UIView, что я всегда использую для пользовательских представлений, вы можете использовать его самостоятельно с несколько простых шагов:

Нажмите Ctrl + N, чтобы добавить новую категорию Objective-C. В файле заголовка добавить эти строки:

// This category let the UIView that using it to load a XIB with the same name as the UIView.h & .m files easily. 
// See: MyContentWaitingSong custom view for reference. 
@interface UIView (NibLoading) 

+ (id)loadInstanceFromNib; 

@end 

чем в файле .m добавить эти строки:

// This category let the UIView that using it to load a XIB with the same name as the UIView.h & .m files easily. 
// See: MyContentWaitingSong custom view for reference. 
@implementation UIView (NibLoading) 

+ (id)loadInstanceFromNib 
{ 
    UIView *result = nil; 

    NSArray* elements = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil]; 

    for (id anObject in elements) { 
     if ([anObject isKindOfClass:[self class]]) { 
      result = anObject; 
      break; 
     } 
    } 

    return result; 
} 

@end 

Чем вы можете использовать его в своем классе пользовательского вида, просто импортировать категорию и реализации метод инициализации, как это:

- (id)init 
{ 
    self = [YourCustomClassName loadInstanceFromNib]; 
    if (self) 
    { 
     // Your initial implementation 
    } 
    return self; 
} 

чем ваша реализация должна выглядеть так:

YourCustomClassName *someName = [[YourCustomClassName alloc] init]; 
someName.frame = frame; 
[self.view addSubView:someName]; 

Удачи.

+1

Хороший ответ, я использую что-то вроде этого (но немного сложнее). Единственное, что это ответ на другой вопрос. –

Смежные вопросы