iPhone UIView - Resize Frame to Fit Subviews

2019-01-13 07:32发布

Shouldn't there be a way to resize the frame of a UIView after you've added subviews so that the frame is the size needed to enclose all the subviews? If your subviews are added dynamically how can you determine what size the frame of the container view needs to be? This doesn't work:

[myView sizeToFit];

10条回答
再贱就再见
2楼-- · 2019-01-13 07:57

Whatever module that dynamically added all these subviews had to know where to put them (so they relate properly, or so they don't overlap, etc.) Once you know that, plus the size of the current view, plus the size of the subview, you have all you need to determine if the enclosing view needs to be modified.

查看更多
混吃等死
3楼-- · 2019-01-13 08:03

You could also add the following code to calculate subviews position.

[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
查看更多
我命由我不由天
4楼-- · 2019-01-13 08:05

Old question but you could also do this with a recursive function.

You might want a solution that always works no matter how many subviews and subsubviews,...

Update : Previous piece of code only had a getter function, now also a 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)
        }
    }
}
查看更多
淡お忘
5楼-- · 2019-01-13 08:07

Here is a swift version of the accepted answer, also small change, instead of extending it this method gets the view as a variable and returns it.

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
}

Heres the extending version:

/// 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)
}
查看更多
Explosion°爆炸
6楼-- · 2019-01-13 08:09
[myView sizeToFit];

Should work, why don't you check the CGRect before and after?

查看更多
冷血范
7楼-- · 2019-01-13 08:17

When you make your own UIView class, consider overriding IntrinsicContentSize in the subclass. This property is called by OS to know the recommended size of your view. I will put code snippet for C# (Xamarin), but the idea is the same:

[Register("MyView")]
public class MyView : UIView
{
    public MyView()
    {
        Initialize();
    }

    public MyView(RectangleF bounds) : base(bounds)
    {
        Initialize();
    }

    Initialize()
    {
        // add your subviews here.
    }

    public override CGSize IntrinsicContentSize
    {
        get
        {
            return new CGSize(/*The width as per your design*/,/*The height as per your design*/);
        }
    }
}

This returned size depends completely on your design. For example, if you just added a label, then width and height is just the width and height of that label. If you have more complex view, you need to return the size that fits all your subviews.

查看更多
登录 后发表回答