Rotating a View in Layoutsubviews

Rotating a view in layoutSubviews

The problem with the code in the question seems to be that the transformations keep getting added to each other. In order to fix this, the solution is to reset the transformations every time, that is, set it to the identity transform.

rotationView.transform = CGAffineTransformIdentity

Here is a partial implementation that shows the key parts.

import UIKit
@IBDesignable class UIVerticalTextView: UIView {

var textView = UITextView()
let rotationView = UIView()

var underlyingTextView: UITextView {
get {
return textView
}
set {
textView = newValue
}
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override init(frame: CGRect){
super.init(frame: frame)
self.setup()
}

override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}

func setup() {

rotationView.backgroundColor = UIColor.redColor()
textView.backgroundColor = UIColor.yellowColor()
self.addSubview(rotationView)
rotationView.addSubview(textView)

// could also do this with auto layout constraints
textView.frame = rotationView.bounds
}

override func layoutSubviews() {
super.layoutSubviews()

rotationView.transform = CGAffineTransformIdentity // *** key line ***

rotationView.frame = CGRect(origin: CGPointZero, size: CGSize(width: self.bounds.height, height: self.bounds.width))
rotationView.transform = translateRotateFlip()
}

func translateRotateFlip() -> CGAffineTransform {

var transform = CGAffineTransformIdentity

// translate to new center
transform = CGAffineTransformTranslate(transform, (self.bounds.width / 2)-(self.bounds.height / 2), (self.bounds.height / 2)-(self.bounds.width / 2))
// rotate counterclockwise around center
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
// flip vertically
transform = CGAffineTransformScale(transform, -1, 1)

return transform
}
}

My most recent implementation is most likely to be found in this github link.

How to layout subviews on device rotation in iOS 10

Add and use didRotateFromInterfaceOrientation orientation delegate method.

To layout subviews use autoresizingMask property of UIView,

Like,

YourView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

From the UIView documentation:

When a view’s bounds change, that view automatically resizes its
subviews according to each subview’s autoresizing mask.

Changing autoresizingMask to other than None will trigger layoutSubviews.

So, you can use below code to layout subviews using didRotateFromInterfaceOrientation delegate method.

-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {

[self.view layoutIfNeeded];
[self.view setNeedsLayout];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

//....Other code
}

-(void)layoutSubviews{

//write your code to draw here
}

layoutSubviews called twice when rotating

I had the same question. I found this page to be helpful for me. Is this useful for you?

EDIT:
Here is the summary of the page (copied):

  • init does not cause layoutSubviews to be called (duh)
  • addSubview causes layoutSubviews to be called on the view being added, the view it’s being added to (target view), and all the subviews of the target view
  • setFrame intelligently calls layoutSubviews on the view having it’s frame set only if the size parameter of the frame is different
  • scrolling a UIScrollView causes layoutSubviews to be called on the scrollView, and it’s superview
  • rotating a device only calls layoutSubview on the parent view (the responding viewControllers primary view)
  • removeFromSuperview – layoutSubviews is called on superview only (not show in table)

viewDidLayoutSubviews in Autolayout with rotation on UIPageViewController

From two of the answers, it looks like viewDidLayoutSubviews maybe the
wrong place to layout the views. I'm trying to find where this should
be done and have the view's know their bounds and orientation but
before they are visible on the screen.

I would subclass UIScrollView and override there layoutSubviews, which will be called for you by the system only when needed and when all the variables (orientation, size, etc.) have the proper values.

Custom UIView layoutSubviews with orientation and animations?

I have recently started overriding viewDidLayoutSubviews (many times instead of viewWillAppear) in my UIViewControllers.

Yes viewDidLayoutSubviews is called on rotations. (from comment)

The method fires after all the internal layouts have already been completed so all finalized frames should be setup, but still give you the time you need to make adjustments before the the view is visible and shouldn't have any issues with animations because you are not already inside an animation block.

viewcontroller.m

- (void)viewDidLayoutSubViews {
// At this point I know if an animation is appropriate or not.
if (self.shouldRunAnimation)
[self.fuView runPrettyAnimations];
}

fuView.m

- (void)runPrettyAnimations {
// My animation blocks for whatever layout I'd like.
}

- (void)layoutSubviews {
// My animations are not here, but non animated layout changes are.
// - Here we have no idea if our view is visible to the user or may appear/disappear
// partway through an animation.
// - This also might get called far more than we intend since it gets called on
// any frame updates.
}


Related Topics



Leave a reply



Submit