I am trying to achieve a layout of buttons very similar to Apple's inbuilt Calculator app:
I am using autolayout to position the buttons, and drawing a 0.5px border on each button, aiming for a 1px gap between buttons (like the calc app, closeup showing pixels above, from a retina device).
Border applied by :
btn.layer.borderWidth=0.5f;
btn.layer.borderColor=[[UIColor blackColor] CGColor];
and the layout is set up using Interface Builder.
It almost works; but there is some variability in the gap between buttons - for example the gap between the "1,2,3,thru" row and the "4,5,6,and" row is 2 pixels, but the gap between the "7,8,9" and "cl,0,@" rows is only one pixel.
Constraints are :
In interface builder and at runtime I don't see any autolayout errors; and a debugger dump of the autolayout info gives me:
po [[UIWindow keyWindow] _autolayoutTrace]
*<UIWindow:0x10908a560> - AMBIGUOUS LAYOUT
| *<UILayoutContainerView:0x109136140>
| | *<UINavigationTransitionView:0x10908ef80>
| | | *<UIViewControllerWrapperView:0x109138870>
| | | | *<UIView:0x1090e6d10>
| | | | | *<UILabel:0x1090d5bb0>
| | | | | *<UIButton:0x1090d27e0>
| | | | | | <UIButtonLabel:0x1091c9190>
| | | | | *<UIButton:0x1090844c0>
| | | | | | <UIButtonLabel:0x1091c7990>
| | | | | *<UIButton:0x109088b60>
| | | | | | <UIButtonLabel:0x1091c6190>
| | | | | *<UIButton:0x1090e2ce0>
| | | | | | <UIButtonLabel:0x1091c4990>
| | | | | *<UIButton:0x1090e4e50>
| | | | | | <UIButtonLabel:0x1091c3190>
| | | | | *<UIButton:0x1090db730>
| | | | | | <UIButtonLabel:0x1091c1990>
| | | | | *<UIButton:0x109068f50>
| | | | | | <UIButtonLabel:0x1091c0190>
| | | | | *<UIButton:0x10906db80>
| | | | | | <UIButtonLabel:0x1091be990>
| | | | | *<UIButton:0x1090d23a0>
| | | | | | <UIButtonLabel:0x1091bd190>
| | | | | *<UIButton:0x1090c8520>
| | | | | | <UIButtonLabel:0x1091bb990>
| | | | | *<UIButton:0x1090c9090>
| | | | | | <UIButtonLabel:0x1091ba190>
| | | | | *<UIButton:0x1090c5680>
| | | | | | <UIButtonLabel:0x1091b8990>
| | | | | *<UIButton:0x1090d7fa0>
| | | | | | <UIButtonLabel:0x1091b7190>
| | | | | *<UIButton:0x1090cc820>
| | | | | | <UIButtonLabel:0x1091b5990>
| | | | | *<UIButton:0x10909dda0>
| | | | | | <UIButtonLabel:0x1091b4190>
| | | | | *<UIButton:0x1090c8090>
| | | | | | <UIButtonLabel:0x1091b2990>
| | | | | *<UIButton:0x1090c8e30>
| | | | | | <UIButtonLabel:0x1091b1190>
| | | | | *<UIButton:0x1090d5390>
| | | | | | <UIButtonLabel:0x1091af990>
| | | | | *<UIButton:0x10d30d260>
| | | | | | <UIButtonLabel:0x1091ae190>
| | | | | *<UIButton:0x10909a6a0>
| | | | | | <UIButtonLabel:0x1091ac990>
| | | | | *<UIButton:0x1090cca40>
| | | | | | <UIButtonLabel:0x109161160>
| | | | | *<UIButton:0x10d30ea90>
| | | | | | <UIButtonLabel:0x109156460>
| | | | | *<UIButton:0x1090da9e0>
| | | | | | <UIButtonLabel:0x109177ad0>
| | | | | *<_UILayoutGuide:0x1090e6dd0> - AMBIGUOUS LAYOUT
| | | | | *<_UILayoutGuide:0x1090ce080> - AMBIGUOUS LAYOUT
| | <UINavigationBar:0x10907da60>
| | | <_UINavigationBarBackground:0x109087240>
| | | | <_UIBackdropView:0x1090899f0>
| | | | | <_UIBackdropEffectView:0x10908b110>
| | | | | <UIView:0x10908bbb0>
| | | | <UIImageView:0x1090877a0>
| | | <UINavigationItemView:0x10916bc30>
| | | | <UILabel:0x10917f810>
| | | <UINavigationItemButtonView:0x1090ee060>
| | | | <UILabel:0x1090ee5d0>
| | | <_UINavigationBarBackIndicatorView:0x109098c80>
Can anyone offer any hints on how to achieve a "pixel perfect" layout like this with Autolayout? Or should I be doing this programatically instead?
Use the keyboard shortcut ⇧ Shift ⇧ Shift A to add auto layout. Figma will create a frame around your selection, and add auto layout.
Auto Layout constraints allow us to create views that dynamically adjust to different size classes and positions. The constraints will make sure that your views adjust to any size changes without having to manually update frames or positions.
Control-Dragging ConstraintsIf you drag more or less horizontally, you get options to set the horizontal spacing between the views, and options to vertically align the views. If you drag more or less vertically, you get options to set the vertical spacing, and options to align the views horizontally.
Layer borders are drawn inside the views bounds, so you aren't going to see a "gap" between the buttons, but the effect of two borders abutting each other. This isn't going to work in the non-retina simulator or devices, since it can't draw a half-pixel, and Autolayout doesn't align views on half-pixels.
For a layout like the one above I'd be giving a fixed height to the buttons (or to one button, and making the others equal it) and letting the black view take up the remaining space. It's always best to have at least one (ideally, exactly one) variable element in a full-screen layout basically to cover rounding errors.
It sounds at the moment like you have one fixed element (the black view) and the buttons are basically "take the remaining height and divide it between yourselves", which will only work if the remaining height divides perfectly.
I tried to set horizontal/vertical spaces between views equal to 0.5. The color of parent view acts as border color. It looks ugly in IB, it cannot layout views properly but resulting layout on device looks perfect.
In interface builder:
On simulator:
Constraints are a bit tricky. For each row:
You can apply constraints to multiple items at once. In order to apply leading/trailing spaces between buttons, place them without intersection in desired order before applying.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With