My iOS Apps iOS Software Mac OS Software Classic Software HyperCard Software |
MacTidingsNU » Sork Software » Auto Layout Demo |
Updated 14-11-03 |
|
Putta Auto Layout Demo
The cat is out of bag and we now know that the new iPhone resolutions starts at a rather strange 1334 x 750 pixels which is 667 x 375 points, neither of which is a binary number. PlayerCentral The four player bar views are subviews of their superview PlayerCentral that will also host the constraints that controls their final layout. In addition, it has four constraints that define the size and position of a central spacer view – the PlaceView (tinted yellow here for clarity). This will provide the central limits for the player views. The player bars are created from a xib using loadNibNamed:, receive their proper transforms, and are then added to the PlayerCentral. The bars’ pertinent parameters are listed below (CCW from the bottom bar). The first set represents the original non auto layout code that includes a translation (shown at the top), in addition to the required rotations. CGAffineTransform translate = CGAffineTransformMakeTranslation(160.0, -113.0); frame = (0 273; 273 47); tag = 0; frame = (273 47; 47 273); transform = [0, -1, 1, 0, 160, -113]; tag = 1; frame = (47 0; 273 47); transform = [-1, -0, 0, -1, 47, -273]; tag = 2; frame = (0 0; 47 273); transform = [-0, 1, -1, -0, -113, -160]; tag = 3; The auto layout constraints will make the same work as the translation, however, making this unnecessary. The second set shows how the translations have been included in the frames. frame = (0 273; 273 47); tag = 0; frame = (113 160; 47 273); transform = [0, -1, 1, 0, 0, 0]; tag = 1; frame = (0 273; 273 47); transform = [-1, -0, 0, -1, 0, 0]; tag = 2; frame = (113 160; 47 273); transform = [-0, 1, -1, -0, 0, 0]; tag = 3;
To prevent the creation of autoresizing constraints,
Please note that the yellow LED simulation at the left end of the bar that originally was a part of the background image now has its own ImageView, as this must move when the bar becomes wider. More about that later. [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[Place][Player0]|" options:0 metrics:nil views:views]]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[Player0][Player1]" options:0 metrics:nil views:views]]; Using the visual format language makes it easy to see what is happening. The vertical constraints start from the central spacer to the first player view, a second constraint pins the player view to the bottom edge of the superview, that is PlayerCentral. Horisontally, the player view is pinned to the superview's right edge and then in its other end to the next vertical player view. The four added constraints look like this when logged: NSLAYOUTCONSTRAINT:0XA46F6C0 V:[PLACEVIEW:0X8E822A0]-(0)-[PLAYERVIEW:0X8E83FF0] NSLAYOUTCONSTRAINT:0XA46F710 V:[PLAYERVIEW:0X8E83FF0]-(0)-| (NAMES: '|':PLAYERCENTRAL:0X8E81EF0 ) NSLAYOUTCONSTRAINT:0XA4755C0 H:|-(0)-[PLAYERVIEW:0X8E83FF0] (NAMES: '|':PLAYERCENTRAL:0X8E81EF0 ) NSLAYOUTCONSTRAINT:0XA474B40 H:[PLAYERVIEW:0X8E83FF0]-(0)-[PLAYERVIEW:0XA474F30]
The demo game controller has an action method that changes the width of the PlayerCentral by manipulating its width constraint. How to find this? One way would have been to hook it up to an outlet in IB. Instead, we look it up by searching for a
The player views have all expanded to fill out the larger space! Three things, the background image must expand correctly, the LEDs look awful, and why 396 pixels? Let’s address one thing at a time.
All the stretching happens in the left side and at the bottom, leaving the top highlight mostly unchanged. The end caps outside the first and third lines are unchanged, while the thin pink part is replaced by the resizable area between the left and inner slicing handles. Use the Attributes inspector to specify wether the resizable area should stretch or tile. - (void)layoutSubviews { [super layoutSubviews]; // Get the lamp view UIView *theLamp = self.playerIndicator; // And its new vertical offset CGFloat offset = theLamp.frame.origin.y; [UIView animateWithDuration:0.31 animations:^{ // Animate the lamp view into the correct horizontal position self.lampLeading.constant = offset; [self layoutIfNeeded]; } completion:^(BOOL finished){ // Could be used to insert or remove a view }]; }
We must call super on this method and then gets the lamp offset from the image view Y origin. Here I have already prepared a property that is an outlet to the constraint that pins the lamp view to the player view left edge. The offset is applied to the constant of this constraint and the lamp is centered again after a call to
Since the Player label is constrained to the right edge of the lamp view, the label shrinks when the lamp moves to the right. To make the text move too, and not distort or clip, its Content Mode is set to Left. The following image shows the distorted views caused by the Auto Layout “bug” in iOS 8. I reported this in June, it still not fixed, and probably will not be. In addition, later betas introduced some very strange math were a simple 0 becomes weird numbers: frame = (47 -4.9738e-14; 273 47); transform = [-1, 3.6739403974420594e-16, -3.6739403974420594e-16, -1, 0, 0];
The new behavior in iOS 8 is that all layout is calculated with respect to the untransformed geometry. This will return the frames of my rotated views to thier unrotated state and mess up the view content. The demo code You can download the demo project below and play with it in Xcode. Hopefully, there is something in it that will benefit your own efforts to conquer Auto Layout. As many other powerful concepts, this is not always that obvious and easy. For more, have a look at the book by Erica Sadun iOS Auto Layout Demystified. This can be ordered from Amazon. Version list
Version 1.0 first release. Dec 2013. Downloads
Xcode 5 project for the demo: PlayerAutolayout.zip (81 kB) E-mail your thoughts on the app to: Putta is the simple game with a twist (or two). |