2014-10-30 109 views
0

我創建了一個自定義視圖,該視圖應該出現在應用中的多個視圖控制器中。在IB中使用自定義視圖

所以...我創建了UIView的子視圖,併爲它配備了xib,h和m文件(並在類中設置了xib文件中的視圖),將我的UI添加到視圖xib文件並將它們連接起來作爲IBOutlets:

enter image description here

enter image description here

enter image description here

則...我加入2- UIViews到一個視圖控制器,設置它們的類轉MYCustomView和連接THA的IBOutlets T形的VC:

enter image description here

enter image description here

enter image description here

而且......這是行不通的......

現在......我很熟悉使用NSBundle loadNibNamed:owner:options:方法加載xib的技術。

但是...我真的很想能夠直接在IB中設置MYCustomView的實例(約束,大小等)。

是否有另一種方法可以做到這一點?或者我應該創建'佔位符'UIViews並添加我的MYCustomView實例作爲他們的子視圖?

回答

1

不,你問一個關於從其他筆尖引用筆尖的問題。有些方法可以通過一些awakeAfterUsingCoder:黑客或類似的東西來實現。通常你會檢查view是否沒有子視圖,然後從nib加載視圖,或者創建一些IB-dummy類,它在加載後用目標類替換它自己。所有這些技術都有問題,所以我建議不要這樣做。

所以我建議從代碼加載它,很好的捕獲將使用視圖控制器遏制。

有一些非常酷的東西,相對不久前出現: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 grailAn Update on Nested Nib Loading

1

嗯,我想有兩種可能的方法:

  1. 正如你所提到的使用該技術與loadNibNamed:owner:options
  2. 如果您正在使用故事板,則可以使用所謂的容器視圖。只需在故事板中設置自定義視圖,使用segue連接它即可完成。

對於第二種方法,您需要使用視圖控制器來放置您的自定義視圖,但這應該不是問題。在我看來,使用單獨的視圖控制器來放置視圖控制器邏輯甚至更好。

2

有,我總是使用自定義視圖一些UIView的類別,你可以自己用幾個簡單的步驟使用它:

點擊命令+ 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 

比你可以在你的自定義視圖類中使用它,只需要導入的類別和實施一個init方法像這樣的:

- (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

不錯的答案,我使用類似的東西(但有點複雜)。唯一的問題就是這是另一個問題的答案。 – 2014-10-30 14:39:56