Одинаковый подкласс UIView в нескольких подклассах UIViewController? - PullRequest
0 голосов
/ 12 июля 2011

У меня есть несколько UIViewControllers. Я хотел бы использовать один и тот же подкласс UIView (который идет поверх существующего представления UIViewController) во всех из них. Возможно ли это с помощью Interface Builder?

Я имею в виду, я хотел бы иметь возможность перетаскивать UIView на представление каждого UIViewController и переименовывать класс этого перетаскиваемого UIView в CustomView, и все элементы в CustomView будут отображаться ... это возможно?

Ответы [ 2 ]

2 голосов
/ 13 июля 2011

Исходя из вашего вопроса и вашего ответа на вопрос с высоким содержанием кофеина - чей ответ правильный, но я думаю, что он может быть немного искажен от того, что вы спрашиваете - я думаю, что вы хотите иметь возможность графически создать представление в Интерфейсном Разработчике (так Вы не написали пользовательский подкласс UIView, вы просто упорядочили некоторые UIViews определенным образом, чтобы они все были потомками другого представления), а затем встроили его в несколько контроллеров представления с помощью некоторой косвенной ссылки, чтобы вы могли Вы не копируете и не вставляете одни и те же элементы пользовательского интерфейса, и если вы вносите изменения в одном месте, это изменение вступает в силу везде?

Насколько я знаю, в Interface Builder или Xcode 4 нет встроенного средства для достижения этой цели. XIB - это чистые данные, а у UIViews нет умов для обработки ссылки вне файла.

Что вы можете сделать, так это спроектировать представление, которое вы хотите использовать в одном XIB, называемом, скажем, ReusableView.xib, а затем написать собственный подкласс UIView, который будет выглядеть примерно так:

@implementation ReusableViewTemplate

- (id)initWithCoder:(NSCoder *)aDecoder
{
    // initialise ourselves normally
    self = [super initWithCoder:aDecoder];

    if(self)
    {
        // load everything in the XIB we created
        NSArray *objects = [[NSBundle mainBundle] 
                            loadNibNamed:@"ReusableView" owner:self options:nil];

        // actually, we know there's only one thing in it, which is the
        // view we want to appear within this one
        [self addSubview:[objects objectAtIndex:0]];
    }

    return self;
}

@end

Затем в ваших NIB вставьте UIView, в который вы хотите переместить многоразовое представление, и установите для 'class' значение 'ReusableViewTemplate' или как вы его назвали.

Если вы откроете ReusableView XIB и установите тип родительского представления на ReusableViewTemplate, то вы можете подключить любые элементы UIControl (например, кнопки или переключатели) для подключения к ним. Вы, вероятно, захотите определить какой-то собственный протокол для своего многоразового шаблона представления и перехватить viewDidLoad в любых контроллерах представления, которые используют повторно используемое представление для установки соответствующего делегата.

РЕДАКТИРОВАТЬ: дальнейшие мысли по этому поводу. Я создал пример проекта (в настоящее время на обычном сайте общего доступа к файлам, поэтому может не существовать вечно) с классом ReusableView, который для целей примера содержит вид сегмента и кнопку и выглядит как это:

@implementation ReusableView

/*

    initWithCoder loads the relevant XIB and adds its
    only object, which is a UIView, as a subview of this
    one. If you don't like the double hierachy, you
    could just have a list of views in the XIB and
    addSubviews:, but then it'd much more difficult to
    edit the thing graphically. You could strip the top
    view programmatically, but this is just a simple
    example, so...

*/
- (id)initWithCoder:(NSCoder *)aDecoder
{
    // initialise ourselves normally
    self = [super initWithCoder:aDecoder];

    if(self)
    {
        // load everything in the XIB we created
        NSArray *objects = [[NSBundle mainBundle] 
                                loadNibNamed:@"ReusableView"
                                owner:self
                                options:nil];

        // actually, we know there's only one thing in it, which is the
        // view we want to appear within this one
        [self addSubview:[objects objectAtIndex:0]];
    }

    return self;
}

@synthesize delegate;
@synthesize segmentedControl;
@synthesize button;

/*

    NSObject contains machinery to deal with the possibility
    that a class may be sent a selector to which it doesn't
    respond.

    As of iOS 4, forwardingTargetForSelector: can be used to
    nominate an alternative target for the selector quickly.

    In previous versions of iOS, or in iOS 4 if you don't
    respond to forwardingTargetForSelector:, you may take
    delivery of the problematic invocation and deal with it
    yourself.

    Dealing with the invocation costs more than providing
    a forwarding target for the selector, so its worth having
    both.

    If you're only targeting iOS 4 or above, you needn't
    keep the implementation of forwardInvocation: below.

    What we're doing is declaring a bunch of IBActions so
    that we can wire changes up to them in Interface Builder.
    By failing to implement them and providing the delegate
    as the thing to talk to for any selectors we don't know,
    we're allowing those wirings to be as though assigned
    to the delegate.

*/
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return delegate;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation setTarget:delegate];
    [anInvocation invoke];
}

@end

С интерфейсом:

@interface ReusableView : UIView 
{

    IBOutlet id delegate;

    IBOutlet UISegmentedControl *segmentedControl;
    IBOutlet UIButton *button;

}

@property (nonatomic, assign) id delegate;

@property (nonatomic, assign) UISegmentedControl *segmentedControl;
@property (nonatomic, assign) UIButton *button;

/*

    NB: we're not actually going to implement these. We're
    declaring them for the benefit of Interface Builder / Xcode 4.

    What we'll actually do is, any time we receive a selector
    we don't implement, hand it off to the delegate. So it's a
    quick way of avoiding writing any glue code to pass messages
    from this little reusable view to its delegate.

    A better alternative could define a formal protocol that
    forwards both the changed control and self from the
    reusable view to its delegate. But that's obvious and
    verbose, so has been omitted for the purposes of example.

    The implementation as stands will generate compiler warnings,
    but such is life. To get rid of the warnings, comment out
    the two following lines, but only AFTER you've wired
    everything up in Interface Builder / Xcode 4. They're left
    uncommented here to help draw attention to the point about
    selector/invocation forwarding that you'll see in the
    @implementation.

    !!!!!!!!!!!!!!!

            HENCE:

            delegates MUST implement the following methods.

    !!!!!!!!!!!!!!!

    We could work around that by checking at runtime whether
    the actual delegate implements them and forwarding to
    a dummy object that implements them to do nothing otherwise,
    but that's slightly beyond the point of the example.

*/
- (IBAction)reusableViewSegmentControlDidChange:(id)sender;
- (IBAction)reusableViewButtonWasPressed:(id)sender;

@end

Чистый эффект заключается в том, что если у контроллера представления есть UIView типа ReusableView в XIB, он получает содержимое ReusableVew.xib, вставленное во время выполнения. Если он подключается как делегат ReusableView в Интерфейсном Разработчике / XCode 4 и реализует:

- (IBAction)reusableViewSegmentControlDidChange:(id)sender;
- (IBAction)reusableViewButtonWasPressed:(id)sender;

Затем он получает сообщения от встроенных представлений.

Это достигается очень просто и очень аккуратно в Objective-C с помощью присущей NSObject способности пересылать селекторы (начиная с iOS 4) или вызовы (в более ранних версиях, с более высокой стоимостью), которые он не реализует, а не позволяет исключение.

2 голосов
/ 12 июля 2011

Да, это возможно.Так же, как вы можете иметь (например) несколько UIViewController в вашем проекте, каждый с UIImageView в качестве представления, вы можете сделать то же самое с вашими собственными подклассами UIView.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...