Iphone uiview - изменить размер рамки для поддисков
Должен ли быть способ изменить размер рамки UIView после того, как вы добавили subviews, чтобы кадр был размером, необходимым для того, чтобы заключить все подпункты? Если ваши подпункты добавляются динамически, как вы можете определить, какой размер должен быть ракурсом представления контейнера? Это не работает:
[myView sizeToFit];
Ответы
Ответ 1
Отъезд Не удалось получить UIView sizeToFit, чтобы сделать что-нибудь значимое
Суть в том, что sizeToFit
предназначен для переопределения подклассов и ничего не делает в UIView. Он делает материал для UILabel
, потому что он переопределяет sizeThatFits:
, который вызывается sizeToFit
Ответ 2
Вы также можете добавить следующий код, чтобы вычислить позицию subviews.
[myView resizeToFitSubviews]
UIViewUtils.h
#import <UIKit/UIKit.h>
@interface UIView (UIView_Expanded)
-(void)resizeToFitSubviews;
@end
UIViewUtils.m
#import "UIViewUtils.h"
@implementation UIView (UIView_Expanded)
-(void)resizeToFitSubviews
{
float w = 0;
float h = 0;
for (UIView *v in [self subviews]) {
float fw = v.frame.origin.x + v.frame.size.width;
float fh = v.frame.origin.y + v.frame.size.height;
w = MAX(fw, w);
h = MAX(fh, h);
}
[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, w, h)];
}
@end
Ответ 3
Мне нужно было подобрать объекты, имеющие отрицательную начальную точку, а CGRectUnion
- это способ ObjC сделать это, честно говоря, как кто-то упомянул в комментариях. Сначала давайте посмотрим, как это работает:
Как вы можете видеть ниже, мы предполагаем, что некоторые подъязыки лежат снаружи, поэтому нам нужно сделать две вещи, чтобы сделать это хорошо, не влияя на позиционирование подзонов:
- Переместите рамку вида в верхнее левое положение.
- Переместите подзоны в противоположном направлении, чтобы нейтрализовать эффект.
Изображение стоит тысячи слов.
![demonstration]()
Код стоит миллиарда слов. Вот решение:
@interface UIView (UIView_Expanded)
- (void)resizeToFitSubviews;
@end
@implementation UIView (UIView_Expanded)
- (void)resizeToFitSubviews
{
// 1 - calculate size
CGRect r = CGRectZero;
for (UIView *v in [self subviews])
{
r = CGRectUnion(r, v.frame);
}
// 2 - move all subviews inside
CGPoint fix = r.origin;
for (UIView *v in [self subviews])
{
v.frame = CGRectOffset(v.frame, -fix.x, -fix.y);
}
// 3 - move frame to negate the previous movement
CGRect newFrame = CGRectOffset(self.frame, fix.x, fix.y);
newFrame.size = r.size;
[self setFrame:newFrame];
}
@end
Я подумал, что было бы интересно писать в Swift 2.0. Я был прав!
extension UIView {
func resizeToFitSubviews() {
let subviewsRect = subviews.reduce(CGRect.zero) {
$0.union($1.frame)
}
let fix = subviewsRect.origin
subviews.forEach {
$0.frame.offsetInPlace(dx: -fix.x, dy: -fix.y)
}
frame.offsetInPlace(dx: fix.x, dy: fix.y)
frame.size = subviewsRect.size
}
}
И доказательство игровой площадки:
Обратите внимание, что visualAidView
не перемещается и помогает вам увидеть, как изменяется размер superview
при сохранении позиций подсмотров.
let canvas = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
canvas.backgroundColor = UIColor.whiteColor()
let visualAidView = UIView(frame: CGRect(x: 5, y: 5, width: 70, height: 70))
visualAidView.backgroundColor = UIColor(white: 0.8, alpha: 1)
canvas.addSubview(visualAidView)
let superview = UIView(frame: CGRect(x: 15, y: 5, width: 50, height: 50))
superview.backgroundColor = UIColor.purpleColor()
superview.clipsToBounds = false
canvas.addSubview(superview)
[
{
let view = UIView(frame: CGRect(x: -10, y: 0, width: 15, height: 15))
view.backgroundColor = UIColor.greenColor()
return view
}(),
{
let view = UIView(frame: CGRect(x: -10, y: 40, width: 35, height: 15))
view.backgroundColor = UIColor.cyanColor()
return view
}(),
{
let view = UIView(frame: CGRect(x: 45, y: 40, width: 15, height: 30))
view.backgroundColor = UIColor.redColor()
return view
}(),
].forEach { superview.addSubview($0) }
![playground image]()
Ответ 4
Похоже, ответ Кенни выше, указывает на правильное решение в вопросе, но может иметь забрал неправильную концепцию. UIView
ссылка на класс определенно предлагает систему для создания sizeToFit
, относящихся к вашим пользовательским представлениям.
Переопределить sizeThatFits
, а не sizeToFit
Ваш пользовательский UIView
должен переопределить sizeThatFits
, чтобы вернуть "новый размер, соответствующий помещению в приемнике", однако вы хотите чтобы вычислить это. Вы даже можете использовать математику из другого ответа, чтобы определить свой новый размер (но без воссоздания встроенной системы sizeToFit
).
После sizeThatFits
возвращает числа, относящиеся к его состоянию, вызовы sizeToFit
в ваших пользовательских представлениях начнут вызывать ожидаемые изменения размера.
Как sizeThatFits
работает
Без переопределения sizeThatFits
просто возвращает параметр размера переданного значения (по умолчанию self.bounds.size
для вызовов из sizeToFit
. Хотя у меня есть только пара источники в этой проблеме, похоже, что размер передаваемых данных не рассматривается как строгий спрос.
[sizeThatFits
] возвращает "самый подходящий" размер для элемента управления, который соответствует ограничениям, переданным ему. Метод может (выделить их) решить игнорировать ограничения, если они не могут быть выполнены.
Ответ 5
Старый вопрос, но вы также можете сделать это с помощью рекурсивной функции.
Вам может понадобиться решение, которое всегда работает независимо от того, сколько подпунктов и подзадач,...
Обновление: в предыдущем фрагменте кода была только функция геттера, а теперь и сеттер.
extension UIView {
func setCGRectUnionWithSubviews() {
frame = getCGRectUnionWithNestedSubviews(subviews: subviews, frame: frame)
fixPositionOfSubviews(subviews, frame: frame)
}
func getCGRectUnionWithSubviews() -> CGRect {
return getCGRectUnionWithNestedSubviews(subviews: subviews, frame: frame)
}
private func getCGRectUnionWithNestedSubviews(subviews subviews_I: [UIView], frame frame_I: CGRect) -> CGRect {
var rectUnion : CGRect = frame_I
for subview in subviews_I {
rectUnion = CGRectUnion(rectUnion, getCGRectUnionWithNestedSubviews(subviews: subview.subviews, frame: subview.frame))
}
return rectUnion
}
private func fixPositionOfSubviews(subviews: [UIView], frame frame_I: CGRect) {
let frameFix : CGPoint = frame_I.origin
for subview in subviews {
subview.frame = CGRectOffset(subview.frame, -frameFix.x, -frameFix.y)
}
}
}
Ответ 6
Независимо от того, какой модуль, динамически добавлявший все эти подзадачи, должен был знать, куда их поместить (чтобы они правильно относились или не перекрывались и т.д.). Когда вы это знаете, плюс размер текущего представления, плюс размер подзаголовка, у вас есть все, что вам нужно, чтобы определить, нужно ли изменять вложенный вид.
Ответ 7
Вот быстрая версия принятого ответа, а также небольшое изменение, вместо того, чтобы расширять его, этот метод получает представление как переменную и возвращает его.
func resizeToFitSubviews(#view: UIView) -> UIView {
var width: CGFloat = 0
var height: CGFloat = 0
for someView in view.subviews {
var aView = someView as UIView
var newWidth = aView.frame.origin.x + aView.frame.width
var newHeight = aView.frame.origin.y + aView.frame.height
width = max(width, newWidth)
height = max(height, newHeight)
}
view.frame = CGRect(x: view.frame.origin.x, y: view.frame.origin.y, width: width, height: height)
return view
}
Имеет расширенную версию:
/// Extension, resizes this view so it fits the largest subview
func resizeToFitSubviews() {
var width: CGFloat = 0
var height: CGFloat = 0
for someView in self.subviews {
var aView = someView as! UIView
var newWidth = aView.frame.origin.x + aView.frame.width
var newHeight = aView.frame.origin.y + aView.frame.height
width = max(width, newWidth)
height = max(height, newHeight)
}
frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: width, height: height)
}
Ответ 8
Обновлен ответ @Mazyod на Swift 3.0, работал как шарм!
extension UIView {
func resizeToFitSubviews() {
let subviewsRect = subviews.reduce(CGRect.zero) {
$0.union($1.frame)
}
let fix = subviewsRect.origin
subviews.forEach {
$0.frame.offsetBy(dx: -fix.x, dy: -fix.y)
}
frame.offsetBy(dx: fix.x, dy: fix.y)
frame.size = subviewsRect.size
}
}
Ответ 9
[myView sizeToFit];
Должен ли работать, почему бы вам не проверить CGRect до и после?