UIView никогда не отображается, если он добавлен как подвид в viewDidLoad.

Я пытаюсь программно добавить подвид в контроллер представления, но кажется, что если я добавлю подпредставление в viewDidLoad контроллера представления, все, что я добавил в качестве подпредставления в самом представлении, не отображается в контроллере представления.

Но если я передвину [self.view addSubview:myUIView] в метод init контроллера представления, все будет отрисовано.

Кроме того, если я вызываю те же методы в viewDidAppear, я получаю визуализацию всех элементов, но это происходит сразу после отображения контроллера представления, и я могу видеть, когда элементы визуализируются в контроллере представления.

Это будет мой контроллер представления:

//interface
@class RLJSignInView;
@protocol RLJSignInViewControllerDelegate;


@interface RLJSignInViewController : UIViewController <UITextFieldDelegate>
@property (nonatomic, readwrite) RLJSignInView *signInView;
@property (nonatomic, assign) id<RLJSignInViewControllerDelegate> delegate;
@end


//implementation
#import "RLJSignInViewController.h"
#import "RLJSignInView.h"
#import "RLJSignInViewControllerDelegate.h"
#import "UIColor+RLJUIColorAdditions.h"


@implementation RLJSignInViewController
- (id)init
{
    self = [super init];

    if (self) {
        _signInView = [[RLJSignInView alloc] initWithFrame:self.view.bounds];

        [self.view addSubview:self.signInView];
    }

    return self;
}
- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"%@", self.signInView);

    [self.view setBackgroundColor:[UIColor rgbWithRed:250 green:250 blue:250]];
}
@end

И это будет мой взгляд:

//interface
@interface RLJSignInView : UIView
@property (strong, nonatomic, readwrite) UITextField *username;
@property (strong, nonatomic, readwrite) UITextField *password;
@property (strong, nonatomic, readwrite) UIButton *signIn;
@property (strong, nonatomic, readwrite) UIButton *signUp;
@end


//implementation
#import "RLJSignInView.h"
#import "UITextField+RLJUITextFieldAdditions.h"
#import "UIButton+RLJUIButtonAdditions.h"


@implementation RLJSignInView
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (self) {

        CGRect usernameInputFrame = CGRectMake(10.0, 40.0, self.bounds.size.width - 20, 40);
        CGRect passwordInputFrame = CGRectMake(10.0, 79.0, self.bounds.size.width - 20, 40);
        CGRect signInButtonFrame = CGRectMake(10.0, 160, self.bounds.size.width - 20, 40);
        CGRect signUpButtonFrame = CGRectMake(10.0, 220, self.bounds.size.width - 20, 40);

        UIView *usernameInputLeftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 40)];
        UIView *passwordInputLeftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 40)];

        self.username = [[UITextField alloc] initWithFrame:usernameInputFrame
                                             textAlignment:NSTextAlignmentLeft
                                                 textColor:[UIColor blackColor]
                                               clearButton:UITextFieldViewModeWhileEditing
                                                  leftView:usernameInputLeftView
                                               placeholder:@"Username"
                                           backgroundColor:[UIColor whiteColor]
                                               strokeWidth:2.0
                                               strokeColor:[UIColor lightGrayColor]
                                              keyboardType:UIKeyboardTypeEmailAddress
                                         byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
                                               cornerRadii:CGSizeMake(4.0, 4.0)
                                                    secure:NO];

        self.password = [[UITextField alloc] initWithFrame:passwordInputFrame
                                             textAlignment:NSTextAlignmentLeft
                                                 textColor:[UIColor blackColor]
                                               clearButton:UITextFieldViewModeWhileEditing
                                                  leftView:passwordInputLeftView
                                               placeholder:@"Password"
                                           backgroundColor:[UIColor whiteColor]
                                               strokeWidth:2.0
                                               strokeColor:[UIColor lightGrayColor]
                                              keyboardType:UIKeyboardTypeDefault
                                         byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
                                               cornerRadii:CGSizeMake(4.0, 4.0)
                                                    secure:YES];

        self.signIn = [[UIButton alloc] initWithFrame:signInButtonFrame
                                                title:@"Sign In"
                                          colorNormal:[UIColor whiteColor]
                                     colorHighlighted:[UIColor whiteColor]
                                        colorDisabled:[UIColor whiteColor]
                                     backgroundNormal:[UIColor colorWithRed:82 / 255.0 green:156 / 255.0 blue:201 / 255.0 alpha:1.0]
                                         cornerRadius:4.0];

        self.signUp = [[UIButton alloc] initWithFrame:signUpButtonFrame
                                                title:@"Sign Up"
                                          colorNormal:[UIColor blackColor]
                                     colorHighlighted:[UIColor blackColor]
                                        colorDisabled:[UIColor blackColor]
                                     backgroundNormal:[UIColor whiteColor]
                                         cornerRadius:4.0];

        [self addSubview:self.username];
        [self addSubview:self.password];
        [self addSubview:self.signIn];
        [self addSubview:self.signUp];
    }

    return self;
}
@end

Я не уверен, что я мог бы с этим поделать, но я точно знаю, что не хотел бы, чтобы представление добавлялось в подпредставление при инициализации.

Или, может быть, я неправильно делаю рендеринг подвидов представления. Я был бы признателен за некоторые советы по этому вопросу, если бы кто-нибудь столкнулся с тем же или заметил, что я что-то напутал.


person Roland    schedule 16.11.2013    source источник


Ответы (2)


Не вызывайте self.view внутри вашего метода init. Это приведет к вызову viewDidLoad еще до того, как ваш метод init вернется, что является неправильным поведением.

Вместо этого следуйте этому шаблону:

  • создайте свои объекты (свойства/переменные экземпляра) в init или с помощью ленивого создания экземпляров
  • добавить подвиды в viewDidLoad
  • установить кадры в viewWillLayoutSubviews

Этот шаблон позволит избежать ошибок, подобных той, которую вы разместили здесь, и настроит вас на успешную обработку событий поворота и изменения размера в будущем.

person Aaron Brager    schedule 16.11.2013
comment
Я понимаю, но это относится только к моему контроллеру представления, так как представление не имеет этих методов, поэтому мне нужно добавить подпредставления в метод инициализации, или для этого есть лучший способ? Я не знал о том, что не вызываю self.view в моих методах инициализации, спасибо за информацию :) - person Roland; 17.11.2013
comment
Вы должны добавить представление в viewDidLoad, но предоставить фиксированный фрейм, используя CGRectMake() вместо использования self.view.bounds. - person Leijonien; 17.11.2013
comment
И да, это сработало, как вы предполагали. Единственная проблема сейчас заключается в том, что подвиды в представлении не имеют фреймов, которые они предполагают, из-за того, что границы в точке инициализации равны 0, что я могу с этим поделать? - person Roland; 17.11.2013
comment
Хорошо, причина, по которой у меня был self.bounds, заключалась в том, что я хотел иметь те же границы, что и у контроллера представления. - person Roland; 17.11.2013
comment
Как мне использовать автомакет, и я читал, что это не лучшая идея, и иногда это довольно сложно. Но я не говорю из своего личного опыта, так как я никогда не использовал его - person Roland; 17.11.2013
comment
Неважно, что вы изначально установили для кадра, если вы установили его в viewWillLayoutSubviews. Этот метод всегда будет вызываться в нужное время. - person Aaron Brager; 17.11.2013
comment
@rolandjitsu Если фреймы подпредставлений не настроены должным образом, вам нужно установить их фреймы в методе layoutSubviews вашего подкласса UIView. - person Aaron Brager; 17.11.2013
comment
Кстати, есть ли лучшие методы UIView, которые я могу перезаписать, чтобы добавить подвиды? Или все в порядке, если я сделаю это при инициализации? - person Roland; 17.11.2013
comment
В UIView вы должны сделать это во время инициализации. Имейте в виду, что существует два отдельных метода (initWithFrame: и initWithCoder:) в зависимости от того, создаете ли вы представление программно или в Интерфейсном Разработчике. - person Aaron Brager; 18.11.2013

Возможно, вы используете self.view.bounds слишком рано. Это может сработать, если вы предоставите фрейм начального размера (как это сделал бы IB).

init слишком рано. Представление controller инициализируется, представление еще не загружено, что означает, что представления нет, и границы вернут CGRectZero.

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

viewWillAppear — это первый момент, когда вы можете полагаться на границы представления. Так как он будет изменен в соответствии с ограничениями autoresizingmasks или autolayout.

Вы можете добавить подпредставление в viewDidLoad, но вы должны предоставить начальный кадр (и вы установите правильные маски автоматического изменения размера или ограничения), все должно работать нормально.

person Leijonien    schedule 16.11.2013
comment
Я сам только что написал тот же ответ, вы меня опередили! В частности, при автоматической компоновке представление контроллера представления не будет иметь рамки до тех пор, пока не будет вызван viewDidLayoutSubviews. Итак, вы можете добавить его в viewDidLoad, но, как говорит Лейониен, вам нужно предоставить начальный кадр или установить кадр в viewDidLayoutSubviews. - person jrturton; 17.11.2013