13

I have learned how to rotate a view with Affine Transforms (see here). I have also learned about Auto Layout (see here and here), and even programmatic Auto Layout (see here and here). However, I don't know how to get Auto Layout to work with a rotated view.

This image shows what I would like to do:

enter image description here

I think the trouble comes from the width and the height changing because of the rotation. Is there any way to make a rotated view fill it's superview? Is there some trick to get Auto Layout to work or is it just incompatible after a rotation?

(I've only learned Swift, but I'd be glad to wade through Objective-C answers if that is what you are more familiar with.)

Update

Following @VinayJain's suggestion I did the following:

  • pinned the subview edges to the superview in the storyboard.
  • created IBOutlets for the spacing constraints on all sides of the subview.

    @IBOutlet weak var rightSpace: NSLayoutConstraint!
    @IBOutlet weak var leftSpace: NSLayoutConstraint!
    @IBOutlet weak var topSpace: NSLayoutConstraint!
    @IBOutlet weak var bottomSpace: NSLayoutConstraint!
    
  • rotated the subview

    subview.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
    
  • changed the constraints from the outlets

    self.rightSpace.constant = CGFloat(0)
    self.leftSpace.constant = CGFloat(0)
    self.topSpace.constant = CGFloat(0)
    self.bottomSpace.constant = CGFloat(0)
    

But it was at this point that I realized that I don't really need to change the spacing value. I want the spacing to remain 0. I just need it to adjust itself. However, the rotation messes that up. The effect is shown in the following image:

enter image description here

Community
  • 1
  • 1
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • Did you ever find a solution for this? I tried pinning the top of the subview to the right of the superview (etc for all sides) to no avail. – BFeher Sep 07 '15 at 01:58
  • @BFeher, Yes, I made a custom `UIView` (yellow image above). It is made up of three views: a parent view, a child view, and a grandchild view. The grandchild view is the actual content that I want to show rotated (a text view, etc.). The child view is what is actually rotated. (The grandchild view sits in the child and doesn't know about the rotation.) The child view is programmatically set to be the same size as the parent view. Then you can set constraints on the parent view to arrange it in the storyboard (blue image above). – Suragch Sep 07 '15 at 14:37
  • Check out this [github project](https://github.com/suragch/iOS-Mongol-App-Components/blob/master/Mongol%20App%20Componants/UIMongolTextView.swift) for my current implementation. Look specifically at the `layoutSubviews()` method. It also deal with an orientation change. Its not a perfect solution but it works to set constraints in the storyboard just like any other `UIView`. – Suragch Sep 07 '15 at 14:41
  • 1
    See also [Rotating a view in layoutSubviews](http://stackoverflow.com/questions/30907710/rotating-a-view-in-layoutsubviews) – Suragch Sep 07 '15 at 14:49
  • Thanks! It seems to work, and in my case I don't support more than one layout, so device rotation is not a problem. – BFeher Sep 07 '15 at 23:36
  • In the future I plan to just make a custom view which draws it's own rotated content. Then it should work with autolayout. – Suragch Mar 15 '17 at 10:37

3 Answers3

4

I came across this problem when trying to run external video over HDMI / AirPlay from iOS to a rotated TV screen.

Sometimes, the TV will have a setting to "rotate" the signal 90-degrees or 180-degrees, etc. but often times it will not have that option.

With a "wrapper" view like this, I am able to force the view controller on the external screen to rotate its contents without the contents actually being aware that anything is different.

let contentsView = SomeWildCustomViewUsingAutoLayoutEtc()
let wrapper = RotatingWrapperView(contentsView)
wrapper.translatesAutoresizingMaskIntoConstraints = false
parentView.addSubview(wrapper)
// ...
wrapper.rotation = .upsideDown

Source for RotatingWrapperView: https://github.com/quantcon/UIKit/blob/master/AutoLayoutRotationDemo/Views/RotatingWrapperView.swift

snakeoil
  • 497
  • 4
  • 12
1

After setting up my UI with auto layout, I created a label, rotated it then set the bounds to a view that was already laid out.

let lbl = UILabel()
    lbl.text = Constants.UI.FlightRequest.flightRequest
    lbl.textColor = .white
    lbl.font = UIFont.systemFont(ofSize: 12)
    lbl.rotation = -90
    lbl.textAlignment = .center
    lbl.frame = blueSideBar.bounds //<--- here is where I set the frame
    blueSideBar.addSubview(lbl)

var rotation: Int {
    get {
        return 0
    } set {
        let radians = ((CGFloat.pi) * CGFloat(newValue) / CGFloat(180.0))
        self.transform = CGAffineTransform(rotationAngle: radians)
    }
}
devjme
  • 684
  • 6
  • 12
-2

You can do it with autolayout easily,

  • Create constraints by pinning the edges to superview
  • Create outlets for these constraints(say it leftSpace,rightSpace,topSpace,bottomSpace)

  • Check for rotation, and update these values accordingly

Use this to check for rotation : Check Rotation

Community
  • 1
  • 1
Vinay Jain
  • 1,653
  • 20
  • 28
  • It is only the subview that is being manually rotated, not the orientation of the whole device. However, the logic of your answer still works. I would just replace your "check for rotation" with the point at which I do the AffineTransformRotate. I'll try it out and update later. – Suragch Jun 15 '15 at 09:39
  • @Suragch great, check if it works for you, then if it works you edit my answer according to your requirement – Vinay Jain Jun 15 '15 at 09:41
  • Unfortunately I couldn't get your method to work. I updated my question with the results of trying your solution. – Suragch Jun 15 '15 at 10:57