I need to make below table like structure in one of the apps I am developing. I am creating this table using UITableView & I need my table column width to change based on the screen orientation. I have set constraints for column width & I will assign values to these using the screen width in my viewDidLoad().
However, I am not able to figure out how to re-align these constraints when screen orientation changes. I figured out that viewWillTransition() will be called when orientation is changed & I recalculated the constraints inside that & called setNeedsLayout() for the table view. However, I am not able to make my table view to reset the table column width when screen orientation is changed. I am new to IOS platform and any help will be greatly appreciated.
HDR_parName/HDR_parValue/HDR_minValue/HDR_maxValue
Para1/value1/minvalue1/maxvalue1
Para2/value2/minvalue2/maxvalue2
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
let animationHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called several times during rotation,
// so if you want your tableView change more smooth reload it here too.
self?.tableView.reloadData()
}
let completionHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called when rotation will be completed
self?.tableView.reloadData()
}
coordinator.animateAlongsideTransition(animationHandler, completion: completionHandler)
}
Then tableView datasource and delegate methods will be called, where you can setup elements size according to tableView frame size.
Swift 4
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let animationHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called several times during rotation,
// so if you want your tableView change more smooth reload it here too.
self?.yourTable.reloadData()
}
let completionHandler: ((UIViewControllerTransitionCoordinatorContext) -> Void) = { [weak self] (context) in
// This block will be called when rotation will be completed
self?.yourTable.reloadData()
}
coordinator.animate(alongsideTransition: animationHandler, completion: completionHandler)
}
It is quite simple solution, what you are doing is wrong.
Consider you want full width as your row width.
You don't have to set any constraint to cell width, instead set trailing constraint to your tableview. It will handle all.
If you still face similar issue then try
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
self.view.layoutIfNeeded()
}
let me know if you are still facing the issue.
Related
I have a full-screen UIView. When I rotate the phone the view shrinks a little (and you see the black background) and then expands again to be full-screen. It basically animates as expected.
The other views on the screen also animate accordingly.
Can I prevent this from happening for one specific view?
I would like the full-screen view to just stay full-screen without animation revealing the black background, but maintain that the other views animate their rotation.
Kind of like how Apple does it in the camera app. The "viewfinder" does not animate its rotation, but the buttons do.
I have the following code in my ViewController. liveView is the the full-screen UIView mentioned.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animateAlongsideTransition(in: self.liveView, animation: { (context) in
if let connection = (self.liveView.layer as! AVCaptureVideoPreviewLayer).connection {
connection.videoOrientation = AVCaptureVideoOrientation(ui: UIApplication.shared.statusBarOrientation)
}
}, completion: nil)
}
AVCaptureVideoOrentation is an extension which basically translates UIInterfaceOrientation to AVCaptureVideoOrientation with a switch statement.
Thanks
- Joseph
Did you try self.liveView.layer.removeAllAnimations():
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animateAlongsideTransition(in: self.liveView, animation: { (context) in
if let connection = (self.liveView.layer as! AVCaptureVideoPreviewLayer).connection {
connection.videoOrientation = AVCaptureVideoOrientation(ui: UIApplication.shared.statusBarOrientation)
}
self.liveView.layer.removeAllAnimations()
}, completion: nil)
}
I'm working on this project and I have one scene on the Storyboard.
The scene is a TableViewController.
The table view have a custom prototype cell (linked to CustomCell.swift).
Inside the prototype cell there's a label and a custom UIView (linked to CustomView.swift). These elements have layout constraints relative to the contentView of the prototype cell.
Now, I want the stuff being drawn on my custom view to change when the size of the view changes, so that when the device rotates it is adjusted to that new cell width. Because of the constraints, the frame of CustomView will change when the CustomCell changes size, after the device is rotated. In order to detect this, I added two property observers to CustomView.swift:
override var frame: CGRect {
didSet {
print("Frame was set!")
updateDrawing()
}
}
override var bounds: CGRect {
didSet {
print("Bounds were set!")
updateDrawing()
}
}
When running the project, the second observer works fine when I rotate the device. The first observer does not. My question is why does the first observer not detect that the frame has changed?
.frame is computed from the .bounds and the .center of the view (and the transform), so it does not change. In order to react to rotation override this (starting from iOS8):
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
coordinator.animateAlongsideTransition({ (coordinator) -> Void in
// do your stuff here
// here the frame has the new size
}, completion: nil)
}
I have a UICollectionView that has a width that is a percentage of it's parent. When it rotates I need to know what the size it is going to be, so I can invalidate the layout and redraw the collection view cells to be the new full width. I was using viewWillTransitionToSize:withTransitionCoordinator: method, but the size it returns is of the entire screen. Is there any easy way to get the new frame of a UICollectionView before the orientation change takes effect?
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
print(self.collectionView.frame) // old frame
coordinator.animateAlongsideTransition({ (UIViewControllerTransitionCoordinatorContext) -> Void in
}) { (UIViewControllerTransitionCoordinatorContext) -> Void in
print(self.collectionView.frame) // new frame
}
}
There is a view, which I add constraints in storyboard so it will change its size after screen rotation, then how can I get its height and width after screen rotation? I tried this in a rotation event function like this:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)
{
println("h:\(view.bounds.size.height)")
println("w:\(view.frame.size.width)")
}
but it only give me the size before rotation happen. I would like to get something like:
"now is landscape, height is...width is..."
"now is portrait, height is ...width is..."
in a rotation event function
The function you are using says "Will transition", that means the transition is not completed, so you can not fetch the new size.
You need to use :
dispatch_async(dispatch_get_main_queue()) {
println("h:\(view.bounds.size.height)")
println("w:\(view.frame.size.width)")
}
This code will be executed after the rotation was completed (in the main queue) and the new sizes are available.
Regards.
Swift 3
crom87 answer updated for Swift 3:
override func viewWillTransition( to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator ) {
DispatchQueue.main.async() {
print( "h:\(self.view.bounds.size.height)" )
print( "w:\(self.view.frame.size.width)" )
}
}
I've built detail view in Interface Builder showing informations and photos about some object. Because lenght of informations and number of photos will vary, all is nested in UIScrollView.
Photos are shown in UICollectionView, but I need to always show all contained photos, so I disabled scrolling and dynamically changing Height constraint of UICollectionView by this function (called when finishing rendering cells):
func resizePhotosCollectionView() {
photosCollectionViewHeightConstraint.constant = photosCollectionView.collectionViewLayout.collectionViewContentSize()
}
It works great until this UICollectionView needs resize (typically by device orientation change). I am trying to use UIViewControllerTransitionCoordinator in function:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition(nil) { context in
self.resizePhotosCollectionView()
}
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
but result is jerky because Height constraint changed after transition is complete.
Is there any way how to automatically resize UICollectionView after view transition? If not, how to animate Height constraint change during transition?
Using Xcode 6.1 for target IOS 8.
If I recall correctly, you need to layout the view immediately.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition(nil) { context in
self.resizePhotosCollectionView()
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
Have you tried wrapping your constraint update into a view animation?
photosCollectionViewHeightConstraint.constant =
photosCollectionView.collectionViewLayout.collectionViewContentSize()
photosCollectionView.setNeedsUpdateConstraints()
UIView.animateWithDuration(0.3, animations: { () -> Void in
photosCollectionView.layoutIfNeeded()
})