简体   繁体   中英

Set up constraints which depends on the frame of the superview

I want to set up some width constraints, which depends on the superview width. In fact I want to use auto layout but I need to access the superviews frame to calculate the width of my subviews. All my subviews are added to a UIView not a view controller.

I set up the constraints in the constructor, but I want to change them in updateConstraints .

Constructor:

nfloat initialWidth = (nfloat)Math.Round((Bounds.Size.Width / 7) - (nfloat)(Math.Ceiling(Bounds.Size.Width % 7) / 2));
container0WidthConstraint = NSLayoutConstraint.Create (container0, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, initialWidth);
container1WidthConstraint = NSLayoutConstraint.Create (container1, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, initialWidth);

AddConstraints (new NSLayoutConstraint[] { container0WidthConstraint, container1WidthConstraint });

updateConstraints :

public override void UpdateConstraints ()
{
    nfloat desiredItemWidth = (nfloat)Math.Round(Bounds.Size.Width / 7);
    nfloat remainingWidth = Bounds.Size.Width - desiredItemWidth * 5;

    if (remainingWidth % 2 == 0) {
        // even
        container0WidthConstraint.Constant = remainingWidth / 2;
        container1WidthConstraint.Constant = remainingWidth / 2;
    } else {
        // odd
        container0WidthConstraint.Constant = (nfloat)Math.Floor(remainingWidth / 2);
        container1WidthConstraint.Constant = (nfloat)Math.Ceiling(remainingWidth / 2);
        }

    base.UpdateConstraints ();
}

The code is in C# but I added this only as additional information. Basically, I want to divide the screen in equally sized views. The only way I found which can work is through calculating as seen above.

I need the Bounds.Size.Width but it is always empty when I debug. How can I add constraints which depends on the frame of the superview once it is set?

Edit:

I think the main reason why this doesn't work for me is that this is added as subview and therefore the auto layout system has not finished yet. Where should I place layoutIfNeeded or should I use layoutSubviews ? When trying the latter one I get the error "Auto Layout still required after executing -layoutSubviews". So where should I place my constraints or how should I set up my view hierarchy?

Auto layout error:

"<NSLayoutConstraint:0x7bd11540 H:|-(0)-[UIView:0x7bd16b90]   (Names: '|':TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0 )>",
    "<NSLayoutConstraint:0x7bd11660 H:[UIView:0x7bd16b90]-(0)-[UIView:0x7bd166a0]>",
    "<NSLayoutConstraint:0x7bd114f0 H:[UIView:0x7bd166a0]-(0)-[UIView:0x7bd16a10]>",
    "<NSLayoutConstraint:0x7bd114c0 H:[UIView:0x7bd16a10]-(0)-[UIView:0x7bd163f0]>",
    "<NSLayoutConstraint:0x7bd11490 H:[UIView:0x7bd163f0]-(0)-[UIView:0x7bd15f90]>",
    "<NSLayoutConstraint:0x7bd11460 H:[UIView:0x7bd15f90]-(0)-[UIView:0x7bd15d80]>",
    "<NSLayoutConstraint:0x7bd11410 H:[UIView:0x7bd15d80]-(0)-[UIView:0x7bd15ad0]>",
    "<NSLayoutConstraint:0x7bd113e0 H:[UIView:0x7bd15ad0]-(0)-|   (Names: '|':TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0 )>",
    "<NSLayoutConstraint:0x7bd115c0 UIView:0x7bd16b90.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7bd11820 UIView:0x7bd166a0.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7bd11850 UIView:0x7bd16a10.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7bd11880 UIView:0x7bd163f0.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7bd118b0 UIView:0x7bd15f90.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7bd11270 UIView:0x7bd15d80.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7bd11240 UIView:0x7bd15ad0.width == 0.142857*TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0.width>",
    "<NSLayoutConstraint:0x7b8d6d60 H:|-(0)-[TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0]   (Names: '|':UIView:0x7bc3e1e0 )>",
    "<NSLayoutConstraint:0x7b8ce180 H:[TestSevenEquallySpaced_SevenEquallySpacedViews:0x7bd255e0]-(0)-|   (Names: '|':UIView:0x7bc3e1e0 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x7bd018b0 h=-&- v=-&- UIView:0x7bc3e1e0.height == UIWindow:0x7bc3e710.height>",
    "<NSAutoresizingMaskLayoutConstraint:0x7bd00ea0 h=--- v=--- V:[UIWindow:0x7bc3e710(1024)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7bd11410 H:[UIView:0x7bd15d80]-(0)-[UIView:0x7bd15ad0]>

You should just constrain these views to your view's width rather than a constant calculated from it.

in Objective-c it would look like

[NSLayoutConstraint constraintWithItem:container0
                             attribute:NSLayoutAtrributeWidth
                             relatedBy:NSLayoutRelationEqual
                                toItem:self
                             attribute:NSLayoutAttributeWidth
                            multiplier:(1.0f/7.0f)
                              constant:0];

This would get you a view which is always 1/7 of the width of its superview.

I am guessing in C# it would be

NSLayoutConstraint.Create (container0, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, (1/7), 0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM