How to Rotate a UIview Without The Black Bars

Can I rotate a UIView without the black bars?

You need to do two things to make this happen.

First, the window's root view controller will always resize its view to the size of the window. So your big view needs to be a subview of the root view controller's view (to keep it from being resized down), and your root view controller's view needs to have clipsToBounds set to NO. In fact all ancestors of the big view need to have clipsToBounds set to NO.

Second, when the window rotates, it gives itself black subviews to explicitly hide any views that would otherwise appear outside the window's bounds. It places these black subviews in front of its root view controller's view. You need to move your root view controller's view to the front, like this:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
UIWindow *window = self.view.window;
[window bringSubviewToFront:window.rootViewController.view];
}

How to prevent UIView background from rotating?

I'm not sure I fully understand the question. What I think your question is (if I'm misunderstanding please clarify where I'm getting the question wrong):

  • You have a UIView that is the same size as the device's screen.
  • You want to rotate that view.
  • When you rotate that view the background of the view's parent view can be seen.

I think the only ways to resolve this are either:

A) Make the view you're rotating larger than the screen so that when you rotate the parent view isn't visible. If you do this make sure the parent view isn't set to clip it's subviews otherwise you won't see any difference after resizing.

OR

B) Make the parent view's background color match the color of the view you're rotating. If you don't want to permanently alter the background color of the parent view you can always change the color when you start the animation and revert to the original color when done.

P.S. - I think the "black background behind everything" is the background color of your app's UIWindow. If you want to change that you can do the following (assuming your app delegate has a window property defined but if you used one of the standard Xcode templates to create your app it should):

UIWindow* window = [[UIApplication sharedApplication].delegate window];
[window setBackgroundColor:<Some UIColor>];

How to prevent UIView background from rotating?

I'm not sure I fully understand the question. What I think your question is (if I'm misunderstanding please clarify where I'm getting the question wrong):

  • You have a UIView that is the same size as the device's screen.
  • You want to rotate that view.
  • When you rotate that view the background of the view's parent view can be seen.

I think the only ways to resolve this are either:

A) Make the view you're rotating larger than the screen so that when you rotate the parent view isn't visible. If you do this make sure the parent view isn't set to clip it's subviews otherwise you won't see any difference after resizing.

OR

B) Make the parent view's background color match the color of the view you're rotating. If you don't want to permanently alter the background color of the parent view you can always change the color when you start the animation and revert to the original color when done.

P.S. - I think the "black background behind everything" is the background color of your app's UIWindow. If you want to change that you can do the following (assuming your app delegate has a window property defined but if you used one of the standard Xcode templates to create your app it should):

UIWindow* window = [[UIApplication sharedApplication].delegate window];
[window setBackgroundColor:<Some UIColor>];

Is it possible to change background color of interface rotation

You cannot change the black color as it is actually not a part of the app. What you can do in this case is add a very large (somewhat larger then the screen size) root view and center it. Then place everything else into this view. This way when your app changes orientation the large view will also rotate, but because of it's size it's edges will never reach the screen and the black color will remain hidden.

UITableView in UINavigationController gets under Navigation Bar after rotation

I ran into this problem recently. In my case, it was because I was performing rotations of a navigation controller that was not the root controller of the application window. I was therefore using the rotate notification listener/affine transform/bounds adjustment approach to changing the layout of the navigation controller. This worked all right but produced the results described here. It took me a while to notice that when I rotated to landscape the nav bar's height was not being correctly resized (i.e., from 44 to 32 pixels, the framework's reduced height for landscape mode). The root view controller of my app was responding to willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation, however. That view controller also already knew about the associated navigation controller. I remedied the problem by adding the following code to the willRotateToInterfaceOrientation method:

CGRect frame = self.navViewController.navigationBar.frame;
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
frame.size.height = 44;
} else {
frame.size.height = 32;
}
self.navViewController.navigationBar.frame = frame;

Hope this saves somebody some time in a similar situation.

Force iOS view to not rotate, while still allowing child to rotate

I had this exact problem, and found out quickly there's a lot of bad advice floating around about autorotation, especially because iOS 8 handles it differently than previous versions.

First of all, you don't want to apply a counterrotation manually or subscribe to UIDevice orientation changes. Doing a counterrotation will still result in an unsightly animation, and device orientation isn't always the same as interface orientation. Ideally you want the camera preview to stay truly frozen, and your app UI to match the status bar orientation and size as they change, exactly like the native Camera app.

During an orientation change in iOS 8, the window itself rotates rather than the view(s) it contains. You can add the views of multiple view controllers to a single UIWindow, but only the rootViewController will get an opportunity to respond via shouldAutorotate(). Even though you make the rotation decision at the view controller level, it's the parent window that actually rotates, thus rotating all of its subviews (including ones from other view controllers).

The solution is two UIWindow stacked on top of each other, each rotating (or not) with its own root view controller. Most apps only have one, but there's no reason you can't have two and overlay them just like any other UIView subclass.

Here's a working proof-of-concept, which I've also put on GitHub here. Your particular case is a little more complicated because you have a stack of containing view controllers, but the basic idea is the same. I'll touch on some specific points below.

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var cameraWindow: UIWindow!
var interfaceWindow: UIWindow!

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
let screenBounds = UIScreen.mainScreen().bounds
let inset: CGFloat = fabs(screenBounds.width - screenBounds.height)

cameraWindow = UIWindow(frame: screenBounds)
cameraWindow.rootViewController = CameraViewController()
cameraWindow.backgroundColor = UIColor.blackColor()
cameraWindow.hidden = false

interfaceWindow = UIWindow(frame: CGRectInset(screenBounds, -inset, -inset))
interfaceWindow.rootViewController = InterfaceViewController()
interfaceWindow.backgroundColor = UIColor.clearColor()
interfaceWindow.opaque = false
interfaceWindow.makeKeyAndVisible()

return true
}
}

Setting a negative inset on interfaceWindow makes it slightly larger than the screen bounds, effectively hiding the black rectangular mask you'd see otherwise. Normally you wouldn't notice because the mask rotates with the window, but since the camera window is fixed the mask becomes visible in the corners during rotation.

class CameraViewController: UIViewController {
override func shouldAutorotate() -> Bool {
return false
}
}

Exactly what you'd expect here, just add your own setup for AVCapturePreviewLayer.

class InterfaceViewController: UIViewController {
var contentView: UIView!

override func viewDidLoad() {
super.viewDidLoad()

contentView = UIView(frame: CGRectZero)
contentView.backgroundColor = UIColor.clearColor()
contentView.opaque = false

view.backgroundColor = UIColor.clearColor()
view.opaque = false
view.addSubview(contentView)
}

override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()

let screenBounds = UIScreen.mainScreen().bounds
let offset: CGFloat = fabs(screenBounds.width - screenBounds.height)

view.frame = CGRectOffset(view.bounds, offset, offset)
contentView.frame = view.bounds
}

override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.All.rawValue)
}

override func shouldAutorotate() -> Bool {
return true
}
}

The last trick is undoing the negative inset we applied to the window, which we achieve by offsetting view the same amount and treating contentView as the main view.

For your app, interfaceWindow.rootViewController would be your tab bar controller, which in turn contains a navigation controller, etc. All of these views need to be transparent when your camera controller appears so the camera window can show through beneath it. For performance reasons you might consider leaving them opaque and only setting everything to transparent when the camera is actually in use, and set the camera window to hidden when it's not (while also shutting down the capture session).

Sorry to post a novel; I haven't seen this addressed anywhere else and it took me a while to figure out, hopefully it helps you and anyone else who's trying to get the same behavior. Even Apple's AVCam sample app doesn't handle it quite right.

The example repo I posted also includes a version with the camera already set up. Good luck!

Annoying white border when rotating a view in iPad

This is a guess:

It's possible that one of your views has a backgroundColor set to white, and it is completely covered by another view. During a rotation, perhaps floating point errors cause one border to show slightly through that edge.

To investigate this case, you can use the undocumented method [UIView recursiveDescription] to get a quick look at your view hierarchy (no need to submit code with that method, it's just for debugging). Once you know which views are near the bottom, you can print out their backgroundColors, or just set them all to [UIColor clearColor].

Also, I'm guessing you already know this one, but it can be useful to set window.backgroundColor = [UIColor clearColor] at the start of your code!



Related Topics



Leave a reply



Submit