iPhone UIView - 调整框架以适应子视图
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iPhone UIView - 调整框架以适应子视图相关的知识,希望对你有一定的参考价值。
在添加子视图后,是否应该有一种方法来调整UIView的框架大小,以便框架是包含所有子视图所需的大小?如果动态添加子视图,您如何确定容器视图的框架需要的大小?这不起作用:
[myView sizeToFit];
看看Having trouble getting UIView sizeToFit to do anything meaningful
要点是sizeToFit
用于子类来覆盖,并且在UIView中没有做任何事情。它为UILabel
做了一些东西,因为它覆盖了由sizeThatFits:
调用的sizeToFit
[myView sizeToFit];
应该工作,为什么不在前后检查CGRect?
您还可以添加以下代码来计算子视图位置。
[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
我需要使子视图具有负的原点,而CGRectUnion
是ObjC的做法,老实说,正如评论中提到的那样。首先,让我们看看它是如何工作的:
正如您在下面所看到的,我们假设一些子视图位于外部,因此我们需要做两件事来使其看起来很好,而不会影响子视图的定位:
- 将视图框移动到最左上方的位置
- 将子视图移动到相反的方向以否定效果。
一张图片胜过千言万语。
代码值十亿字。这是解决方案:
@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) }
它看起来像Kenny 's answer指向referenced question的正确解决方案,但可能已经带走了错误的概念。 UIView
class reference绝对建议一个使sizeToFit
与您的自定义视图相关的系统。
Override sizeThatFits
, not sizeToFit
您的自定义UIView
s需要覆盖sizeThatFits
以返回“适合接收者子视图的新大小”,但是您希望计算此值。你甚至可以使用another answer的数学来确定你的新尺寸(但没有重新创建内置的sizeToFit
系统)。
在sizeThatFits
返回与其状态相关的数字后,在您的自定义视图上调用sizeToFit
将开始导致预期的调整大小。
How sizeThatFits
works
没有覆盖,sizeThatFits
只返回传入的大小参数(默认为self.bounds.size
来自sizeToFit
的调用。虽然我在这个问题上只有couple sources,但似乎传入的大小不被视为严格的需求。
[
sizeThatFits
]返回适合传递给它的约束的控件的“最合适”大小。如果不能满足约束,该方法可以(强调他们的)决定忽略约束。
更新了@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
}
}
旧问题,但您也可以使用递归函数执行此操作。
无论有多少子视图和子子视图,您可能想要一个始终有效的解决方案......
更新:上一段代码只有一个getter函数,现在也是一个setter。
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)
}
}
}
无论动态添加所有这些子视图的模块都必须知道放置它们的位置(因此它们正确关联,或者它们不重叠等)。一旦你知道了,加上当前视图的大小,加上大小的在子视图中,您可以确定是否需要修改封闭视图。
这是一个接受答案的快速版本,也是一个小变化,而不是扩展它,这个方法将视图作为一个变量并返回它。
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)
以上是关于iPhone UIView - 调整框架以适应子视图的主要内容,如果未能解决你的问题,请参考以下文章