Мне нужно измерить высоту простого VC на основе автомакета для заданной ширины. Например — простой UIViewController
только с одной меткой, которая позиционируется с использованием начального, конечного, верхнего и нижнего ограничений для корневого представления VC. VC должен иметь фиксированный размер нет, но автоматически адаптироваться к содержимому метки.
Это только пример, конечно, ВК может иметь другой контент, который влияет на размер.
Как я могу рассчитать размер VC для заданной ширины и содержимого метки, не добавляя его в иерархию представлений?
Задний план:
Я использую сторонний элемент управления FormSheet, который позволяет легко отображать любой ViewController в виде листа формы с различными стилями, переходами и т. д. Единственным недостатком является то, что перед представлением VC необходимо указать фиксированный размер листа.
Хотя это отлично работает для VC со «статическим» содержимым / фиксированными размерами, даже ярлык с разными текстами для разных языков может нарушить дизайн.
Таким образом, я ищу что-то вроде этого:
ContentViewController *contentVC = [ContentViewController new];
CGRect contentBounds = [SomeClass calculateAutoLayoutHeightForView:contentVC.view withFixedWidth:500];
[ThirPartyFormSheetController presentController:contentVC withSize:contentBounds];
Как это может быть сделано?
Извините, но я не вижу, как это связано с вопросом :-) Речь идет не об автоматическом изменении размера метки, а об автоматическом изменении размера представления VC до заданной ширины и содержимого метки.
@AndreiHerford - элемент управления «стороннего» не работает с автоматическим макетом? Если это так, вы хотите получить высоту загруженного представления ContentViewController
на основе «целевой ширины», которую вы определяете самостоятельно? Правильно ли настроены ограничения автоматического макета в ContentViewController
?
@AndreiHerford - какой элемент управления «Сторонний бланк» вы используете?
Я использую MZFormSheetController, и, насколько мне известно, он поддерживает только формы фиксированного размера. Однако это только один вариант использования, когда мне нужно программно вычислить высоту макета для заданной ширины. Было бы здорово решить проблему с формами, но общее решение было бы идеальным.
Примечание: у ViewController'ов нет ни высоты, ни размеров, поскольку они являются просто классом, управляющим представлениями. Если у вас есть VC, вы обычно добавляете к нему представления, и эти представления имеют фреймы (высоту и т. д.), обычно основной UIView, прикрепленный к VC, находится с помощью VC.view
@AndreiHerford - я опубликовал ответ с примером использования systemLayoutSizeFittingSize:UILayoutFittingCompressedSize
для определения высоты, но ... я быстро взглянул на MZFormSheetController
, и определенно кажется, что вы не используете имеют для установки размера ... он будет использовать авто- макет для автоматической установки размера.
Быстрый: Если все, что вам нужно, это рассчитать высоту на основе текста метки, вы можете использовать это решение.
https://stackoverflow.com/a/25187891/7848711
Спасибо, но речь идет не об измерении метки (это был только пример), а о полном размере ВК.
Учитывая ширину, вы можете использовать systemLayoutSizeFittingSize:UILayoutFittingCompressedSize
, чтобы определить, какой будет высота после того, как авто-макет выполнит свою работу.
Предполагая, что ограничения в представлении для показа настроены правильно:
CGFloat w = 500.0;
[loadedView.widthAnchor constraintEqualToConstant:w].active = YES;
// caluclate the size using FittingCompressedSize
CGSize contentBounds = [loadedView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
Вот простой пример (нужно только назначить класс ViewController
контроллеру представления в раскадровке... IBOutlets не нужны). Множество комментариев в коде должно все прояснить:
//
// ViewController.h
// Created by Don Mag on 4/8/19.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
//
// ViewController.m
// Created by Don Mag on 4/8/19.
//
#import "ViewController.h"
#import "FormViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// add a button we'll use to show the form VC
UIButton *b = [UIButton new];
b.translatesAutoresizingMaskIntoConstraints = NO;
[b setTitle:@"Show Form" forState:UIControlStateNormal];
[b setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[b setBackgroundColor:[UIColor redColor]];
[self.view addSubview:b];
[NSLayoutConstraint activateConstraints:
@[
[b.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:20.0],
[b.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:0.75],
[b.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor]
]
];
[b addTarget:self action:@selector(loadAndShowForm:) forControlEvents:UIControlEventTouchUpInside];
}
- (void) loadAndShowForm:(id)sender {
// instantiate the form view controller
FormViewController *vc = [FormViewController new];
// get a reference to its view
UIView *v = vc.view;
// use auto-layout
v.translatesAutoresizingMaskIntoConstraints = NO;
// set the label text in the form view
vc.topLabel.text = @"This is a bunch of text for the TOP label in the Form VC";
vc.bottomLabel.text = @"This is a bunch of text for the BOTTOM label in the Form VC. It's enough text to cause a few lines of word-wrap, assuming we're running on an iPhone.";
// specify a width for the form view
// we'll use width of current view minus 60 (30-pts on each side)
CGFloat w = self.view.frame.size.width - 60.0;
[v.widthAnchor constraintEqualToConstant:w].active = YES;
// caluclate the size using FittingCompressedSize
CGSize contentBounds = [v systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
// because we set the width constraint, we now have the "compressed" height
//[ThirdPartyFormSheetController presentController:contentVC withSize:contentBounds];
// debugging from here down
NSLog(@"Auto-layout resulting size: %@", [NSValue valueWithCGSize:contentBounds]);
// set the height for the form view
[v.heightAnchor constraintEqualToConstant:contentBounds.height].active = YES;
// add it to the view, so we can confirm the height calculation
[self.view addSubview:v];
// center it on the view
[NSLayoutConstraint activateConstraints:
@[
[v.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[v.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]
]
];
}
@end
//
// FormViewController.h
// Created by Don Mag on 4/8/19.
//
#import <UIKit/UIKit.h>
@interface FormViewController : UIViewController
@property (strong, nonatomic) UILabel *topLabel;
@property (strong, nonatomic) UITextField *theTextField;
@property (strong, nonatomic) UILabel *bottomLabel;
@end
//
// FormViewController.m
// Created by Don Mag on 4/8/19.
//
#import "FormViewController.h"
@interface FormViewController ()
@end
@implementation FormViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
// create a multi-line "top label"
_topLabel = [UILabel new];
_topLabel.backgroundColor = [UIColor cyanColor];
_topLabel.text = @"Hello Top Label";
_topLabel.numberOfLines = 0;
// create a text field
_theTextField = [UITextField new];
_theTextField.backgroundColor = [UIColor greenColor]; // just to make it easy to see
_theTextField.borderStyle = UITextBorderStyleRoundedRect;
_theTextField.text = @"The Text Field";
// create a multi-line "bottom label"
_bottomLabel = [UILabel new];
_bottomLabel.backgroundColor = [UIColor cyanColor];
_bottomLabel.text = @"Hello Bottom Label";
_bottomLabel.numberOfLines = 0;
// we're using auto-layout and constraints
_topLabel.translatesAutoresizingMaskIntoConstraints = NO;
_theTextField.translatesAutoresizingMaskIntoConstraints = NO;
_bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
// add to view
[self.view addSubview:_topLabel];
[self.view addSubview:_theTextField];
[self.view addSubview:_bottomLabel];
// these elements and constraints will define the height of the content
[NSLayoutConstraint activateConstraints:
@[
// constrain top label leading, trailing and top to top of view, all at 20-pts
[_topLabel.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20.0],
[_topLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
[_topLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0],
// constrain text field leading and trailing, and top to bottom of top label, all at 20-pts
[_theTextField.topAnchor constraintEqualToAnchor:_topLabel.bottomAnchor constant:20.0],
[_theTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
[_theTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0],
// constrain bottom label leading, trailing and top to bottom of text field, all at 20-pts
[_bottomLabel.topAnchor constraintEqualToAnchor:_theTextField.bottomAnchor constant:20.0],
[_bottomLabel.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-20.0],
[_bottomLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0],
// AND constrain bottom label to bottom of view at 20-pts
[_bottomLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0]
]
];
}
@end
Результат (добавление загруженного представления VC в качестве подпредставления - см. комментарии в коде):
и с дополнительным текстом, чтобы показать автоматический расчет высоты:
Если вы измените количество текста для меток (установлено в ViewController.m
), вы увидите, что высота рассчитана правильно.
Вы пробовали
sizeToFit
? Это метод наUIView
, который изменит размер метки до желаемого размера. Вы можете получить результат из свойстваframe
после его вызова. Не уверен, что вы можете вызвать его в корневом представлении VC, но оно должно работать в представлении ярлыка.