2

I'm using ios 9 sdk. I created this view hierarchy setup with autoloayout:

----- Top
  | 30
----- CustomView (A)
  |
  |
-----
  | 0
----- Bot

I'm trying to create a second CustomView (call it B) behind the first (call it A), scaled by 80% in both directions, and above A by 5 points. So only the top of B is visible.

This should be easy, but it is not. Applying a -5 points translation and a .8 scaling on B moves B down instead of up, because autolayout seems to use the anchor point (set to middle by default) to position B: it seems it detects that a scaling has been applied and recenters B vertically - moving it down.

Changing the Anchor point to (x=0.5,y=1) moves A and B up by half their size, i don't understand why. So it does not fix the problem.

Any idea ?

Edit: some code

var card = new CardView();
InsertSubview(card, 0);

card.TranslatesAutoresizingMaskIntoConstraints = false;
this.AddConstraints(
            card.AtTopOf(this, 30),
            card.WithSameWidth(this).WithMultiplier(.95f),
            card.WithSameCenterX(this),
            card.AtBottomOf(this)
            );

 var transform = CGAffineTransform.MakeTranslation(0, -10);
 transform.Scale(.8f,.8f);
 Transform = transform;

Result: card is not at 20pts from top, it is at about 50pts, beside its original position of 30pt.

Softlion
  • 12,281
  • 11
  • 58
  • 88

2 Answers2

1

You're adding the wrong constraints. After some experimentation I got the results you want. The key seems to be to pin the center Y of the background view to the top of the foreground view, this then offsets the vertical shift given when changing the anchor point.

The following code in a playground gives the results you want:

import UIKit
import XCPlayground

let view = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 400, height:400)))
view.backgroundColor = UIColor.whiteColor()
XCPlaygroundPage.currentPage.liveView = view

let a = UIView()
a.translatesAutoresizingMaskIntoConstraints = false
a.backgroundColor = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.5)
view.addSubview(a)
a.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 30).active = true
a.widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true
a.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true

let b = UIView()
b.translatesAutoresizingMaskIntoConstraints = false
b.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 1)
b.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
view.addSubview(b)
view.sendSubviewToBack(b)
NSLayoutConstraint.activateConstraints([
    b.centerYAnchor.constraintEqualToAnchor(a.topAnchor),
    b.widthAnchor.constraintEqualToAnchor(a.widthAnchor),
    b.heightAnchor.constraintEqualToAnchor(a.heightAnchor),
    b.centerXAnchor.constraintEqualToAnchor(a.centerXAnchor)
])
let translate = CGAffineTransformMakeTranslation(0.0, -10)
let scale = CGAffineTransformMakeScale(0.8, 0.8)
b.transform = CGAffineTransformConcat(translate, scale)

Results:

enter image description here

jrturton
  • 118,105
  • 32
  • 252
  • 268
  • I don't understand why it works, but it works. Any real explanation ? Thank you so much... I lost 2 days on this, was desperate and ready to remove autoloayout. – Softlion May 02 '16 at 09:21
  • Like I said it's the interplay between anchor points and autolayout - it's always been a bit horrible (see http://stackoverflow.com/questions/12943107/how-do-i-adjust-the-anchor-point-of-a-calayer-when-auto-layout-is-being-used) but in your case you're moving the anchor point from the center to the top, which offsets the frame by 50% of the height, so pinning the center to the top instead of the two tops together reverses that. – jrturton May 02 '16 at 09:24
  • In the question you refer to, in the updated blog post, it is written that anchor and transforms are not used by autoloayout anymore since ios8. It seems to be untrue. Or i don't understant the blog post. – Softlion May 02 '16 at 09:40
0

The two possible approaches I see are:
- scale first, then add it to the view hierarchy
or
- change the anchorpoint of view B before you add it to the view hierarchy. Then you can transform it the way you want.

Helge Becker
  • 3,219
  • 1
  • 20
  • 33
  • I can't scale first as it this scale will be changed with animation. I've tryed you 2nd suggestion and it does not work: the vertical middle of A (and B too) is moved at the top of the screen. Wtf with autoloayout ? – Softlion May 02 '16 at 08:26
  • Each view has an achorpoint. changing only view B should do the trick. Unless view A is a subview of view B - in that case will A move with B since its part of it. Also if there is a close relationship through Autolayout. Would need to look at the properties. There re several pitfalls. – Helge Becker May 02 '16 at 08:35
  • View A and B are 2 instances of the same class. If i hange only view B, then the center of view B does move at the top of the main screen. – Softlion May 02 '16 at 08:42