Если у вас есть представление, которому нужно определенным образом разложить свои подвиды, общий подход заключается в создании собственного подкласса представления и переопределении его метода layoutSubviews
. Система автоматически отправляет layoutSubviews
представлению в разное время, в том числе при изменении размера представления. Если система выполняет автоматический запуск, она отправит вам layoutSubviews
из блока анимации автоматического поворота, поэтому вам не нужно беспокоиться об анимации изменений в кадрах ваших подпредставлений.
Это немного усложняется, когда ваш вид представляет собой вид с прокруткой, потому что UIScrollView
часто отправляет себе layoutSubview
сообщения - каждый раз, когда он его меняет contentOffset
. Так что если вы подкласс UIScrollView
, вы хотите быть эффективными. Вам нужно отслеживать последний размер, для которого вы выложены, и выкладывать заново, только если размер изменился. Примерно так:
@implementation MyScrollView {
CGSize _lastLayoutSize;
}
- (void)forceLayout {
_lastLayoutSize = CGSizeMake(-1, -1);
[self setNeedsLayout];
}
- (void)didAddSubview:(UIView *)view {
// UIView sends itself this whenever a subview is added.
[super didAddSubview:view];
[self forceLayout];
}
- (void)didRemoveSubview:(UIView *)view {
// UIView sends itself this whenever a subview is removed.
[super didAddSubview:view];
[self setNeedsLayout];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGSize mySize = self.bounds.size;
if (CGSizeEqualToSize(mySize, _lastLayoutSize))
return;
_lastLayoutSize = mySize;
static CGFloat const margin = 8;
CGFloat yMax = 0;
CGPoint point = CGPointMake(margin, margin);
BOOL rowIsEmpty = YES;
for (UIView *subview in self.subviews) {
CGRect frame = subview.frame;
CGFloat xNext = point.x + frame.size.width + margin;
if (rowIsEmpty || xNext <= mySize.width) {
rowIsEmpty = NO;
point.x = xNext;
} else {
point.x = margin;
point.y = yMax + margin;
}
frame.origin = point;
subview.frame = frame;
yMax = MAX(yMax, CGRectGetMaxY(frame));
}
self.contentSize = CGSizeMake(mySize.width, yMax + margin);
}