简体   繁体   中英

Aspect ratio NSLayoutConstraint in UITableViewCell is breaks

I'm trying to set appropriate NSLayoutConstraint s for a UIImageView in a UITableViewCell . The desired constraints are as follows:

  • 16:9 aspect ratio
  • 0 leading
  • 0 trailing
  • 11 top
  • 11 bottom

The UIImageView is the sole subview of the cell's contentView. I have set tableView.rowHeight = UITableViewAutomaticDimension and tableView.estimatedRowHeight = 80

2018-03-28 15:52:30.454688-0400 TestApp[28844:694668] [LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x604000486cc0 UIImageView:0x7f91cf670470.width == 1.77778*UIImageView:0x7f91cf670470.height   (active)>",
    "<NSLayoutConstraint:0x604000486e50 H:|-(0)-[UIImageView:0x7f91cf670470]   (active, names: '|':UITableViewCellContentView:0x7f91cf66f7e0 )>",
    "<NSLayoutConstraint:0x604000486ef0 H:[UIImageView:0x7f91cf670470]-(0)-|   (active, names: '|':UITableViewCellContentView:0x7f91cf66f7e0 )>",
    "<NSLayoutConstraint:0x604000486f40 V:|-(11)-[UIImageView:0x7f91cf670470]   (active, names: '|':UITableViewCellContentView:0x7f91cf66f7e0 )>",
    "<NSLayoutConstraint:0x604000486ea0 V:[UIImageView:0x7f91cf670470]-(11)-|   (active, names: '|':UITableViewCellContentView:0x7f91cf66f7e0 )>",
    "<NSLayoutConstraint:0x604000487530 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7f91cf66f7e0.height == 233   (active)>",
    "<NSLayoutConstraint:0x6040004874e0 'UIView-Encapsulated-Layout-Width' UITableViewCellContentView:0x7f91cf66f7e0.width == 375   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x604000486cc0 UIImageView:0x7f91cf670470.width == 1.77778*UIImageView:0x7f91cf670470.height   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Hitting the button "Add Missing Constraints" doesn't add any new constraints. The value 1.77778 is the correct decimal representation for my aspect ratio. I'm not sure why the runtime needs this constraint to be broken.

I have also tried creating a symbolic breakpoint for UIViewAlertForUnsatisfiableConstraints with Action -> Debugger Command expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace] and I'm not finding the print-out helpful as it's printing the whole view hierarchy. I'm not sure what a "AMBIGUOUS LAYOUT for UILayoutGuide" has to do with my UITableView or cell...

•UIWindow:0x7f94bd466e60
|   UITransitionView:0x7f94bd64b860
|   |   •UIView:0x7f94bd468e70
|   |   |   *<UILayoutGuide: 0x6000007bdb20 - "UIViewSafeAreaLayoutGuide", layoutFrame = {{0, 44}, {375, 734}}, owningView = <UIView: 0x7f94bd468e70; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x600000822ec0>>>
|   |   |   *UILabel:0x7f94bd469050'Test App'
|   |   UILayoutContainerView:0x7f94bd610f50
|   |   |   UINavigationTransitionView:0x7f94bd488fa0
|   |   |   |   UIViewControllerWrapperView:0x7f94bd6129d0
|   |   |   |   |   •UIView:0x7f94bd61cea0
|   |   |   |   |   |   *<UILayoutGuide: 0x6040001b7840 - "UIViewSafeAreaLayoutGuide", layoutFrame = {{0, 0}, {375, 690}}, owningView = <UIView: 0x7f94bd61cea0; frame = (0 88; 375 724); autoresize = W+H; layer = <CALayer: 0x6040002370a0>>>
|   |   |   |   |   |   *UITableView:0x7f94be080800
|   |   |   |   |   |   |   FancySDK.ImageCell:0x7f94bf025600'5EC2187C-4839-47A3-83E9-C...'
|   |   |   |   |   |   |   |   •UITableViewCellContentView:0x7f94bd749410
|   |   |   |   |   |   |   |   |   *UIImageView:0x7f94bd749810
|   |   |   |   |   |   |   |   _UITableViewCellSeparatorView:0x7f94bd749a40
|   |   |   |   |   |   |   FancySDK.ArticleCell:0x7f94bd8d9600'18CCDA82-E137-496E-AB0C-5...'
|   |   |   |   |   |   |   |   •UITableViewCellContentView:0x7f94bd49a0a0
|   |   |   |   |   |   |   |   |   *UIView:0x7f94bd48cfa0
|   |   |   |   |   |   |   |   |   |   *UIImageView:0x7f94bd48d180
|   |   |   |   |   |   |   |   |   |   *ic_expand:0x7f94bd48d3b0
|   |   |   |   |   |   |   |   |   |   *UILabel:0x7f94bd49c210'Apple will unveil the nex...'
|   |   |   |   |   |   |   |   |   |   *UILabel:0x7f94bd4a20d0'Apple’s annual Worldwide ...'
|   |   |   |   |   |   |   |   |   |   *UILabel:0x7f94bd49ccd0'https://www.theverge.com/...'
|   |   |   |   |   |   |   |   _UITableViewCellSeparatorView:0x7f94bd4a3990
|   |   |   |   |   |   |   UIImageView:0x7f94bd62f410
|   |   |   |   |   |   |   UIImageView:0x7f94bd62fbf0
|   |   |   |   |   |   *UIView:0x7f94bd61ccc0
|   |   |   •Recommended for You:0x7f94bd611580
|   |   |   |   _UIBarBackground:0x7f94bd614750
|   |   |   |   |   UIImageView:0x7f94bd615000
|   |   |   |   _UINavigationBarLargeTitleView:0x7f94bd50ff60'Recommended for You'
|   |   |   |   |   UILabel:0x7f94bd4822f0
|   |   |   |   •_UINavigationBarContentView:0x7f94bd60ad60'Recommended for You'
|   |   |   |   |   *<UILayoutGuide: 0x6040001b7e60 - "BackButtonGuide(0x7f94bd60aa00)", layoutFrame = {{0, 0}, {16, 44}}, owningView = <_UINavigationBarContentView: 0x7f94bd60ad60; frame = (0 0; 375 44); layer = <CALayer: 0x604000235ee0>>>
|   |   |   |   |   *<UILayoutGuide: 0x6040001b7d80 - "LeadingBarGuide(0x7f94bd60aa00)", layoutFrame = {{16, 0}, {24, 44}}, owningView = <_UINavigationBarContentView: 0x7f94bd60ad60; frame = (0 0; 375 44); layer = <CALayer: 0x604000235ee0>>>
|   |   |   |   |   *<UILayoutGuide: 0x6040001b7ca0 - "TitleView(0x7f94bd60aa00)", layoutFrame = {{46, 0}, {321, 44}}, owningView = <_UINavigationBarContentView: 0x7f94bd60ad60; frame = (0 0; 375 44); layer = <CALayer: 0x604000235ee0>>>
|   |   |   |   |   *<UILayoutGuide: 0x6040001b7bc0 - "TrailingBarGuide(0x7f94bd60aa00)", layoutFrame = {{367, 0}, {0, 44}}, owningView = <_UINavigationBarContentView: 0x7f94bd60ad60; frame = (0 0; 375 44); layer = <CALayer: 0x604000235ee0>>>
|   |   |   |   |   *<UILayoutGuide: 0x6040001b7ae0 - "UIViewLayoutMarginsGuide", layoutFrame = {{16, 0}, {343, 44}}, owningView = <_UINavigationBarContentView: 0x7f94bd60ad60; frame = (0 0; 375 44); layer = <CALayer: 0x604000235ee0>>>
|   |   |   |   |   *_UIButtonBarStackView:0x7f94bd62d8d0
|   |   |   |   |   |   *<UILayoutGuide: 0x6040001b8020 - "UIButtonBar.flexibleSpaceEqualSizeLayoutGuide", layoutFrame = {{0, 0}, {8, 0}}, owningView = <_UIButtonBarStackView: 0x7f94bd62d8d0; frame = (16 0; 24 44); layer = <CALayer: 0x604000237f40>>>- AMBIGUOUS LAYOUT for UILayoutGuide:0x6040001b8020'UIButtonBar.flexibleSpaceEqualSizeLayoutGuide'.minX{id: 446}, UILayoutGuide:0x6040001b8020'UIButtonBar.flexibleSpaceEqualSizeLayoutGuide'.minY{id: 447}, UILayoutGuide:0x6040001b8020'UIButtonBar.flexibleSpaceEqualSizeLayoutGuide'.Width{id: 367}, UILayoutGuide:0x6040001b8020'UIButtonBar.flexibleSpaceEqualSizeLayoutGuide'.Height{id: 448}
|   |   |   |   |   |   *<UILayoutGuide: 0x6040001b81e0 - "UIButtonBar.minimumInterItemSpaceLayoutGuide", layoutFrame = {{0, 0}, {8, 0}}, owningView = <_UIButtonBarStackView: 0x7f94bd62d8d0; frame = (16 0; 24 44); layer = <CALayer: 0x604000237f40>>>- AMBIGUOUS LAYOUT for UILayoutGuide:0x6040001b81e0'UIButtonBar.minimumInterItemSpaceLayoutGuide'.minX{id: 449}, UILayoutGuide:0x6040001b81e0'UIButtonBar.minimumInterItemSpaceLayoutGuide'.minY{id: 450}, UILayoutGuide:0x6040001b81e0'UIButtonBar.minimumInterItemSpaceLayoutGuide'.Height{id: 451}
|   |   |   |   |   |   *<UILayoutGuide: 0x6040001b7a00 - "UIButtonBar.minimumInterGroupSpaceLayoutGuide", layoutFrame = {{0, 0}, {8, 0}}, owningView = <_UIButtonBarStackView: 0x7f94bd62d8d0; frame = (16 0; 24 44); layer = <CALayer: 0x604000237f40>>>- AMBIGUOUS LAYOUT for UILayoutGuide:0x6040001b7a00'UIButtonBar.minimumInterGroupSpaceLayoutGuide'.minX{id: 452}, UILayoutGuide:0x6040001b7a00'UIButtonBar.minimumInterGroupSpaceLayoutGuide'.minY{id: 453}, UILayoutGuide:0x6040001b7a00'UIButtonBar.minimumInterGroupSpaceLayoutGuide'.Height{id: 454}
|   |   |   |   |   |   *<UILayoutGuide: 0x6040001b74c0 - "UIViewLayoutMarginsGuide", layoutFrame = {{0, 0}, {24, 44}}, owningView = <_UIButtonBarStackView: 0x7f94bd62d8d0; frame = (16 0; 24 44); layer = <CALayer: 0x604000237f40>>>
|   |   |   |   |   |   *UIButton:0x7f94bd51de30
|   |   |   |   |   |   |   UIImageView:0x7f94bd6210f0
|   |   |   |   |   *UILabel:0x7f94bd6298a0'Recommended for You'
|   |   |   |   +_UINavigationBarModernPromptView:0x7f94bd488da0
|   |   |   |   |   *UILabel:0x7f94bd4893d0
|   |   |   UIActivityIndicatorView:0x7f94bd531500
|   |   |   |   UIImageView:0x7f94bd507950

Legend:
    * - is laid out with auto layout
    + - is laid out manually, but is represented in the layout engine because translatesAutoresizingMaskIntoConstraints = YES
    • - layout engine host

Any feedback is welcome. Thank you

The main reason behind this problem is that initially autolayout assumes a fixed height (until dynamic height is being calculated ) constraint (Required) for the cell's contentView which conflicts with your own constraints and it appears here UIView-Encapsulated-Layout-Height , you can solve this by lowering the priority of the bottom constraint of the imageView to be 999 instead of 1000 ( Required )

Explain

your current width = 375 and aspect ratio = 16 / 9

then imageView height will = (375*9)/16.0 = 210.9

  • 11 in top and 11 in bottom

total = 211 + 11 + 11 = 233 > 80 (estimatedRowHeight)

The problem is that aspect ratio will conflict with your other constraints whenever they don't evaluate to 16:9. Setting leading and trailing constraints will evaluate to a certain width, also setting top and bottom constraints will evaluate to a certain height. The ratio width:height must be the same as your aspect ratio to not create a conflict.

There are several solutions to this. The one you probably want is to replace your leading and trailing constraints with a horizontal center constraint. This will let the aspect ration decide how wide your view should be while center it in the cell.

UPDATE: To clarify how the aspect ratio constraint work, it acts as a lock between your height and your width, enforcing them to keep a set ratio between them. So, if you set one of them, the aspect ratio constraint will effectively set the other one for you. Therefore you shouldn't set both width and height constraints when you have an aspect ratio constraint.

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