0

I am sublassing either an UIImageView or UIView for generating simple color tiles with digits. If I am using UIImageView, I use initWithImage method. If I use UIView, the method initWithFrame is being used. Either red square image or programmatically generated red view is used for initialization.
The problem can be seen on two screenshots: when initWithImage is being used - everything works fine. If initWithFrame method is being used, I am ending with multiple white views without any information created in even order with normal views. All the screenshots and code attached.

This how it looks when initializing using initWithImage: initWithImage

- (id)initWithImage:(UIImage *)image {
    self = [super initWithImage:image];
    if (self) {
//Some non-important, label-related stuff.
        [self addSubview:self.numberLabel];
    }
    return self;
}

And this is how it looks with initWithFrame:
initWithFrame

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.redView = [self redViewWithFrame:frame];
        [self addSubview:self.redView];
//label-related stuff
    }
    return self;
}


- (UIView *)redViewWithFrame:(CGRect)frame {
    UIView *view = [[UIView alloc] initWithFrame:frame];
    view.backgroundColor = [UIColor redColor];
    view.alpha = 1;
    return view;
}    

And the for-loop, calling these initializers from another class (UIScrollView subclass). The label value is being set after the view had been initialized.

- (void)setNumberOfBlocks:(NSInteger)numberOfBlocks {
    _blocks = [[NSMutableArray alloc] init];

    CGSize contentSize;
    contentSize.width = BLOCK_WIDTH * (numberOfBlocks);
    contentSize.height = BLOCK_HEIGHT;

    self.contentSize = contentSize;

    for (int i = 0; i < numberOfBlocks; i++) {
        CGFloat totalWidth = BLOCK_WIDTH * i;
        CGRect frame = CGRectMake(0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);

        frame.origin.x = totalWidth;


        BlockView *view = [[BlockView alloc] initWithImage:[UIImage imageNamed:@"block.png"]];
        OR!!!
        BlockView *view = [[BlockView alloc] initWithFrame:frame];


        view.frame = frame;
        NSString *number = [NSString stringWithFormat:@"%ld", (long)i + 1];
        view.numberLabel.text = number;


        [self addSubview:view];
        [_blocks addObject:view];
    }
}

Googling gave me the impression that this is very common problem, but I haven't found any solution how to beat this. Moreover, I still do not understand, why numbers are in totally right order, the only problem is view position.

Richard Topchii
  • 7,075
  • 8
  • 48
  • 115

2 Answers2

1

I think you should set the frame origin to (0,0) in redViewWithFrame in ordre to hâve superposed views

Idali
  • 1,023
  • 7
  • 10
  • Your solution also worked well, and you answered 1st, but I decided to chose rdelmar's answer because it is more correct (using bounds instead of changing frame's property). Still, get +1 from me! =) – Richard Topchii Oct 12 '14 at 03:25
1

The problem is that you're setting the frame of the red view to the superview's frame instead of its bounds. Since the red view is a subview of the BlockView, its frame needs to be relative to its superview, which you get with bounds (its not clear why you even need the red view, as opposed to setting the background color of the block view to red).

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.redView = [self redViewWithFrame:self.bounds];
        [self addSubview:self.redView];
//label-related stuff
    }
    return self;
}
rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • Although, both solutions helped me, I decided to use rdelmar's solution because it is better (bounds is actually frame with origin set to (0,0)). For some reason I decided to use redView instead of backgroundColor property - which is the correct way. In some parts of the project I use backgroundcolor, maybe this is old part... So thank you for this. Still, your answer helped me a lot, because in label initialization its better also to use bounds instead of frame. The only comment I would like to leave is that you shoud call bounds using `self.bounds` accessor, not just `bounds`. – Richard Topchii Oct 12 '14 at 03:20
  • 1
    @RichardTopchiy, yeah leaving self out was a typo. – rdelmar Oct 12 '14 at 04:05