2015-03-26 1 views
2

В документации layoutSubviews, Apple говорит:Как реализовать sizeToFit, если это зависит от layoutSubviews?

Вы не должны вызывать этот метод напрямую.

Я пытаюсь реализовать sizeToFit. Я хочу, чтобы он помещал узкую ограничительную рамку во все подзоны. Перед определением такого ограничивающего прямоугольника мне нужно подобрать надстройки. Это означает, что я должен позвонить layoutSubviews, на что Apple хмурится. Как я могу решить эту дилемму, не нарушая правила Apple?

- (void)layoutSubviews 
{ 
    [super layoutSubviews]; 

    self.view0.frame = something; 
    self.view1.frame = somethingElse; 
} 

- (void)sizeToFit 
{ 
    [self layoutSubviews]; 

    self.frame = CGRectMake(
    self.frame.origin.x, 
    self.frame.origin.y, 
    MAX(
     self.view0.frame.origin.x + self.view0.frame.size.width, 
     self.view1.frame.origin.x + self.view1.frame.size.width 
    ), 
    MAX(
     self.view0.frame.origin.y + self.view0.frame.size.height, 
     self.view1.frame.origin.y + self.view1.frame.size.height 
    ) 
); 
} 
+1

Обратите внимание, что вы не должны переопределять '-sizeToFit'. Скорее реализуйте '-sizeThatFits:'. –

ответ

4

Не следует переопределить -sizeToFit. Вместо этого переопределите -sizeThatFits:, который внутренне вызывается -sizeToFit с текущим размером границ представления.

Вы не должны переопределять этот метод. Если вы хотите изменить информацию о размерах по умолчанию для своего представления, вместо этого замените sizeThatFits:. Этот метод выполняет любые необходимые вычисления и возвращает их этому методу, который затем производит изменение. - UIView Class Reference


Также не то, что даже если бы вы переопределять -sizeToFit, нет, скорее всего, никаких оснований для немедленного выполнения макета. Вы ограничиваете размер только размера, т. Е. Устанавливаете его размер границ. Это вызывает вызов -setNeedsLayout, обозначая вид как , нуждающийся в макете. Но если вы не хотите анимировать представление, новый макет не обязательно будет применяться сразу.

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


Обычно я это делаю. Отлично работает.

#pragma mark - Layout & Sizing 

- (void)layoutSubviews 
{ 
    [self calculateHeightForWidth:self.bounds.size.width applyLayout:YES]; 
} 

- (CGSize)sizeThatFits:(CGSize)size 
{ 
    CGFloat const width = size.width; 
    CGFloat const height = [self calculateHeightForWidth:width applyLayout:NO]; 

    return CGSizeMake(width, height); 
} 

- (CGFloat)calculateHeightForWidth:(CGFloat)width applyLayout:(BOOL)apply 
{ 
    CGRect const topViewFrame = ({ 
     CGRect frame = CGRectZero; 
     ... 
     frame; 
    }); 

    CGRect const bottomViewFrame = ({ 
     CGRect frame = CGRectZero; 
     ... 
     frame; 
    }); 

    if (apply) { 
     self.topView.frame = topViewFrame; 
     self.bottomView.frame = bottomViewFrame; 
    } 

    return CGRectGetMaxY(bottomViewFrame); 
} 

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

Можно легко настроить код для других стилей компоновки.

-3

Если вы хотите, чтобы заставить layoutSubviews случиться, но не хочу называть его непосредственно, установите флаг needsLayout, а затем попросить его макет.

[self setNeedsLayout]; 
[self layoutIfNeeded]; 
+0

Это очень плохая идея. Вызов '-sizeThatFits:' никогда не должен приводить к изменению макета. Нет гарантии, что представление будет измерено в этом измерении позже, и вы можете перемещаться по подзонам без видимых причин и недопустимых позиций. Кроме того, '-layoutIfNeeded' распространяется по любым подзонам, что может быть ненужным действием для немедленного выполнения. –

0

Я думаю, что очень редко вам понадобится использовать фрейм при использовании автоматической компоновки. Учитывая, что вы хотите решить проблему, не нарушая правила Apple, я бы предложил использовать способ автоматической компоновки:

Установочные ограничения для определения размера вида контейнера.

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

Например, вы можете установить ограничение, такие как:

constraints

Обратите внимание, что view0 и view1 необходимы установить как ширину и высоту ограничения.

Когда вы создаете экземпляр вида где-то в своем проекте, вам больше не нужно устанавливать ограничение ширины и высоты. Автоматическая компоновка угадывает свой размер (называемый intrinsicContentSize) ограничениями, которые вы ранее настраивали.

Смежные вопросы