防止旋转 UIView 子视图,允许旋转同级子视图
Prevent rotating UIView subview, allow rotating sibling subviews
我有一个 UIViewController
,其中包含几个 UIView
和一个 UILabel
,它以全屏显示,嵌入在 UINavigationController
中。在非紧凑型高度环境(纵向)中,我希望盒子彼此堆叠,标签位于下方 - 这按预期工作。现在,当旋转到一个紧凑的高度环境(风景)时,视图当然会重新定位,所以现在盒子的宽度增加了,高度减少了。我不想要那种行为。相反,我想始终将框定位为好像 iPhone 是纵向的,但标签应该像导航栏一样旋转,以便它在当前方向上保持可读。 (这意味着在这种情况下,由于导航栏,视图的高度会受到更多限制。)
一张图片有助于更好地解释:
所以问题是,如何在 UIViewController
中仍然支持横向方向的同时防止旋转特定 UIView
?
我见过其他类似的问题,但他们使用过时的方法来检测特定设备方向的旋转,这与 iOS 8+ 无关。这个问题就是在考虑大小类的时候如何做到这一点。我相信解决方案将使用 viewWillTransitionToSize
和 animateAlongsideTransition
,但我并不完全清楚到底需要做什么。
在这种情况下我使用的是框架布局,而不是自动布局。所有视图都是以编程方式创建的。这些框实际上是 UIView
子类的子视图,该子类根据父视图的框架在框中布置和绘制内容。
在UIViewController
中:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topPosition = self.topLayoutGuide.length
boxesContainer.frame = CGRectMake(20, topPosition, self.view.frame.size.width - 40, (self.view.frame.size.height - topPosition) / 1.5)
boxesContainer.updateLayout()
}
在盒子容器中UIView
:
func updateLayout() {
box1.frame = // something based on self.frame
box2.frame = // ...
}
我想出了一个解决方案。本质上,我检测视图的宽度是否大于高度,如果是,则旋转包含框的视图。在第一次显示视图控制器和尺寸发生变化时执行此操作。然后进行计算以根据需要更新此视图的框架。重要的是,盒子容器视图使用其 frame.size.width
和 frame.size.height
的 min
来放置盒子。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.optimizeForSize(self.view.bounds.size)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//calculate frame for the box container based on current frame
//...
boxContainer.updateLayout()
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (conext: UIViewControllerTransitionCoordinatorContext) -> Void in
self.optimizeForSize(size)
self.view.setNeedsLayout() //needed for iOS 8
}, completion: nil)
}
func optimizeForSize(size: CGSize) {
if size.width > size.height {
self.boxContainer.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI / 2.0))
} else {
self.colorPicker.transform = CGAffineTransformIdentity
}
}
我有一个 UIViewController
,其中包含几个 UIView
和一个 UILabel
,它以全屏显示,嵌入在 UINavigationController
中。在非紧凑型高度环境(纵向)中,我希望盒子彼此堆叠,标签位于下方 - 这按预期工作。现在,当旋转到一个紧凑的高度环境(风景)时,视图当然会重新定位,所以现在盒子的宽度增加了,高度减少了。我不想要那种行为。相反,我想始终将框定位为好像 iPhone 是纵向的,但标签应该像导航栏一样旋转,以便它在当前方向上保持可读。 (这意味着在这种情况下,由于导航栏,视图的高度会受到更多限制。)
一张图片有助于更好地解释:
所以问题是,如何在 UIViewController
中仍然支持横向方向的同时防止旋转特定 UIView
?
我见过其他类似的问题,但他们使用过时的方法来检测特定设备方向的旋转,这与 iOS 8+ 无关。这个问题就是在考虑大小类的时候如何做到这一点。我相信解决方案将使用 viewWillTransitionToSize
和 animateAlongsideTransition
,但我并不完全清楚到底需要做什么。
在这种情况下我使用的是框架布局,而不是自动布局。所有视图都是以编程方式创建的。这些框实际上是 UIView
子类的子视图,该子类根据父视图的框架在框中布置和绘制内容。
在UIViewController
中:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topPosition = self.topLayoutGuide.length
boxesContainer.frame = CGRectMake(20, topPosition, self.view.frame.size.width - 40, (self.view.frame.size.height - topPosition) / 1.5)
boxesContainer.updateLayout()
}
在盒子容器中UIView
:
func updateLayout() {
box1.frame = // something based on self.frame
box2.frame = // ...
}
我想出了一个解决方案。本质上,我检测视图的宽度是否大于高度,如果是,则旋转包含框的视图。在第一次显示视图控制器和尺寸发生变化时执行此操作。然后进行计算以根据需要更新此视图的框架。重要的是,盒子容器视图使用其 frame.size.width
和 frame.size.height
的 min
来放置盒子。
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.optimizeForSize(self.view.bounds.size)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//calculate frame for the box container based on current frame
//...
boxContainer.updateLayout()
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (conext: UIViewControllerTransitionCoordinatorContext) -> Void in
self.optimizeForSize(size)
self.view.setNeedsLayout() //needed for iOS 8
}, completion: nil)
}
func optimizeForSize(size: CGSize) {
if size.width > size.height {
self.boxContainer.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI / 2.0))
} else {
self.colorPicker.transform = CGAffineTransformIdentity
}
}